go 协程管理及传参处理

 基础语法  2022-10-18  admin  1749  2361

Go语言中的goroutine虽然相对于系统线程来说比较轻量级(初始栈大小仅2KB),(并且支持动态扩容),而正常采用java,c++等语言启用的线程一般都是内核态的占用的内存资源一般在4m左右,而假设我们的服务器CPU内存为4G,那么很明显才用的内核态线程的并发总数量也就是1024个,相反查看一下Go语言的协程则可以达到4*1024*1024/2=200w.这么一看就明白了为什么Go语言天生支持高并发

但是在高并发量下的goroutine频繁创建和销毁对于性能损耗以及GC来说压力也不小。充分将goroutine复用,减少goroutine的创建/销毁的性能损耗,这便是grpoolgoroutine进行池化封装的目的。例如,针对于100W个执行任务,使用goroutine的话需要不停创建并销毁100Wgoroutine,而使用grpool也许底层只需要几万个goroutine便能充分复用地执行完成所有任务。



异步执行时并不会保证按照函数注册时的顺序执行

对于异步线程/协程来讲,函数进行异步执行注册时,该函数并未真正开始执行(注册时只在goroutine的栈中保存了变量i的内存地址),

而一旦开始执行时函数才会去读取变量i的值,而这个时候变量i的值已经自增到了10。

清楚原因之后,改进方案也很简单了,就是在注册异步执行函数的时候,把当时变量i的值也一并传递获取;

或者把当前变量i的值赋值给一个不会改变的临时变量,在函数中使用该临时变量而不是直接使用变量i。

// 在注册异步执行函数的时候,把当时变量i的值也一并传递获取;
wg := sync.WaitGroup{}
for i := 0; i < 10; i++ {
	wg.Add(1)
	go func(v int) {
		fmt.Println(v)
		wg.Done()
	}(i)
}
wg.Wait()
//0
//9
//7
//8
//5
//2
//1
//3
//6
//4
//把当前变量i的值赋值给一个不会改变的临时变量,在函数中使用该临时变量而不是直接使用变量i
//采用临时变量的形式来传递当前变量i的值
wg3 := sync.WaitGroup{}
for i := 0; i < 10; i++ {
	wg3.Add(1)
	a := i // 定义局部临时变量
	go func() {
		fmt.Println(a)
		wg3.Done()
	}()
}
wg3.Wait()
//9
//4
//0
//1
//2
//3
//6
//5
//7
//8

错误方式

// 相对于协程,i相当于全局变量
wg2 := sync.WaitGroup{}
for i := 0; i < 10; i++ {
	wg2.Add(1)
	go func() {
		fmt.Println(i)
		wg2.Done()
	}()
}
wg2.Wait()
//10
//10
//10
//10
//10
//10
//10
//10
//10
//10
//全局变量不可行
wg4 := sync.WaitGroup{}
var a int // 定义全局变量
for i := 0; i < 10; i++ {
	wg4.Add(1)
	a = i //
	go func() {
		fmt.Println(a)
		wg4.Done()
	}()
}
wg4.Wait()
//9
//9
//9
//9
//9
//9
//9
//9
//9
//9


如果文章对您有帮助,点击下方的广告,支持一下作者吧!

转载必须注明出处:

go 协程管理及传参处理 —— code.cent123.com

相关推荐


点名工具,抽奖软件

点名工具,抽奖软件

酷炫的倒计时客户端

QQ: 425100867捐赠开发者:

go 的加减乘除运算注意事项,及相互转化问题

packagemain import( &quot;fmt&quot; ) funcmain(){ varintAint=10 varintBint=9 varfloatAfloat64=10 varfloatBfloat64=9 //在Go语言中,操作数的类型必须匹配。也就是说,进行运算时,操作数的类型必须一致或能够进行合理的转换。 //具体来说

AI人脸替换工具离线版V6.0 最新版下载

AI人脸替换工具离线版V6.0 最新版下载下载 解压 双击运行roop_rope_facefusion_V60.exe 文件即可下载链接:https://pan.quark.cn/s/be7953632126AI人脸替换工具离线版V6.0