Go语言一知半解上手记(三)

栏目: IT技术 · 发布时间: 6年前

内容简介:在前两篇文章《在通过上面的小改造,我们把顺序执行的三个函数更改为了并发执行的任务,再通过 sync.WaitGroup 阻塞等待所有任务的完成。我们通过两种不同实现方法上的程序运行时间,也验证了并发确实是节省了时间的。这个例子中对于并发的应用是比较简单的,更深入的使用,就待日后再实战中继续探索吧。

  在前两篇文章《 Go语言一知半解上手记(一) 》、《 Go语言一知半解上手记(二) 》中,我们实现了从读取 xlsx 格式的数据字典开始,到生成 schema 文件,到最后生成代码文件的完整过程。

  在 文章二 中,我们在 template.go 中添加了解析 schema 的方法 analyzeSchema ,在这个方法里,又调用了 generateModelFile、generateControllerFile 来生成最后的代码文件。这两个方法对数据字典格式的针对性及强,参考性不大,因此文章中未进行描述。在后面的实现过程中,我们又增加了 router 中使用的代码脚本的生成功能,最终,在 analyzeSchema 中便有了三个代码文件生成函数的调用,他们目前是顺序执行的,而 Go 语言提供了很方便的并发机制,我们可以再将这三个函数改造成并发执行的过程中初步了解一下Go语言的并发机制。

二、Go语言并发机制初探

1、并发前的 analyzeSchema 函数

// 分析模式文件
func analyzeSchema(schemaPath string, modelTmplPath string, controllerTmplPath string, consoleRouterTmplPath string) error {
	// 1.加载 模式文件
	schema, err := ioutil.ReadFile(schemaPath)
	if err != nil {
		return err
	}
	// 2.转换 模式文件到 数据字典集合 中
	var dataDictSlice []DataDict // 数据字典集合
	if err := Json.Unmarshal(schema, &dataDictSlice); err != nil {
		return err
	}

	// 3.加载模板文件
	modelTmpl, err := template.ParseFiles(modelTmplPath)
	if err != nil {
		return err
	}
	controllerTmpl, err := template.ParseFiles(controllerTmplPath)
	if err != nil {
		return err
	}
	consoleRouterTmpl, err := template.ParseFiles(consoleRouterTmplPath)
	if err != nil {
		return err
	}

	// 4.遍历数据字典集合
	wg := sync.WaitGroup{}
	for _, dataDict := range dataDictSlice {

		// 4.1.生成 collectionInfo 信息
		collectionInfo := map[string]string{
			"Model":          strings.ToUpper(string(dataDict.Collection.Name[0])) + dataDict.Collection.Name[1:],
			"CollectionName": dataDict.Collection.Name,
			"CollectionDesc": dataDict.Collection.Desc,
		}

		// 4.2.生成 所需 脚本
		modelScript, joiSchemaScript, err := getFieldsScript(dataDict)
		if err != nil {
			return nil
		}

		// 4.3.生成 model 代码文件
		err = generateModelFile(modelTmpl, collectionInfo, modelScript)
		if err != nil {
			println(err.Error())
		}

		// 4.4.生成 consoleRouter 代码片段
		err = generateCodeFile(consoleRouterTmpl, "./dist/consoleRouters/"+collectionInfo["CollectionName"]+".js", collectionInfo)
		if err != nil {
			println(err.Error())
		}

		// 4.5.生成 controller 代码文件
		collectionInfo["joiSchemaScript"] = joiSchemaScript
		err = generateCodeFile(controllerTmpl, "./dist/controllers/"+dataDictInfo["collectionInfo"]+".js", collectionInfo)
		if err != nil {
			println(err.Error())
		}

	}

	// 5.没有出错,返回 nil
	return nil
}
复制代码

与上一篇文章中的 analyzeSchema 函数不同之处如下:

  1. “加载模板文件” 时 由一个变成了三个
  2. “遍历数据字典集合” 时 将代码生成函数中所需要用到的信息 提前获取出来,分别是 collectionInfo、modelScript、joiSchemaScript
  3. 生成 controller 文件 及 consoleRouter 文件 的函数合并成了一个函数

2、并发后的 analyzeSchema 函数

// 分析模式文件
func analyzeSchema(schemaPath string, modelTmplPath string, controllerTmplPath string, consoleRouterTmplPath string) error {
	// 1.加载 模式文件
	schema, err := ioutil.ReadFile(schemaPath)
	if err != nil {
		return err
	}
	// 2.转换 模式文件到 数据字典集合 中
	var dataDictSlice []DataDict // 数据字典集合
	if err := Json.Unmarshal(schema, &dataDictSlice); err != nil {
		return err
	}

	// 3.加载模板文件
	modelTmpl, err := template.ParseFiles(modelTmplPath)
	if err != nil {
		return err
	}
	controllerTmpl, err := template.ParseFiles(controllerTmplPath)
	if err != nil {
		return err
	}
	consoleRouterTmpl, err := template.ParseFiles(consoleRouterTmplPath)
	if err != nil {
		return err
	}

	// 4.遍历数据字典集合,采用 协程 并发处理
	wg := sync.WaitGroup{}
	for _, dataDict := range dataDictSlice {

		// 4.1.生成 collectionInfo 信息
		collectionInfo := map[string]string{
			"Model":          strings.ToUpper(string(dataDict.Collection.Name[0])) + dataDict.Collection.Name[1:],
			"CollectionName": dataDict.Collection.Name,
			"CollectionDesc": dataDict.Collection.Desc,
		}

		// 4.2.生成 fields 脚本
		modelScript, joiSchemaScript, err := getFieldsScript(dataDict)
		if err != nil {
			return nil
		}

		// 4.3.生成 model 代码文件
		wg.Add(1)

		go func() {
			defer wg.Done()
			err := generateModelFile(modelTmpl, collectionInfo, modelScript)
			if err != nil {
				println(err.Error())
			}
		}()

		// 4.4.生成 consoleRouter 代码片段
		wg.Add(1)
		go func() {
			defer wg.Done()
			err := generateCodeFile(consoleRouterTmpl, "./dist/consoleRouters/"+collectionInfo["CollectionName"]+".js", collectionInfo)
			if err != nil {
				println(err.Error())
			}
		}()

		// 4.5.生成 controller 代码文件
		collectionInfo["joiSchemaScript"] = joiSchemaScript
		wg.Add(1)
		go func() {
			defer wg.Done()
			err := generateCodeFile(controllerTmpl, "./dist/controllers/"+collectionInfo["CollectionName"]+".js", collectionInfo)
			if err != nil {
				println(err.Error())
			}
		}()

	}
	wg.Wait()

	// 5.没有出错,返回 nil
	return nil
}
复制代码

具体改造如下:

  1. 使用 go func() { } () 将原来的执行方法包起来,实现 goroutine 并发任务
  2. 使用 sync.WaitGroup 来阻塞等待所有任务的完成,wg.Add(1)、wg.Done()、wg.Wait()

三、总结

  通过上面的小改造,我们把顺序执行的三个函数更改为了并发执行的任务,再通过 sync.WaitGroup 阻塞等待所有任务的完成。我们通过两种不同实现方法上的程序运行时间,也验证了并发确实是节省了时间的。这个例子中对于并发的应用是比较简单的,更深入的使用,就待日后再实战中继续探索吧。


以上所述就是小编给大家介绍的《Go语言一知半解上手记(三)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Foundations of PEAR

Foundations of PEAR

Good, Nathan A./ Kent, Allan / Springer-Verlag New York Inc / 2006-11 / $ 50.84

PEAR, the PHP Extension and Application Repository, is a bountiful resource for any PHP developer. Within its confines lie the tools that you need to do your job more quickly and efficiently. You need......一起来看看 《Foundations of PEAR》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

URL 编码/解码
URL 编码/解码

URL 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具