go语言例程:并发中的型参
Posted 懒散的狒狒
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言例程:并发中的型参相关的知识,希望对你有一定的参考价值。
这是一个golang官网上贴出的例程:
for _, v := range []string{"a", "b", "c"} {
go func() {
fmt.Println(v)
}()
}
它在很多go语言面试中都有被问到。首先它的运行结果是:
c c c
但背后的工作原理面试者阐述起来通常会有遗漏。这个涉及到的go语言知识点包括:
循环变量的对象内存分配;
并发中内存的读写特性;
形参的内存分配;
但是在v
被更新的过程中,goroutine并发函数不能获取到v
的值,这就涉及到go语言并发内存的读写互斥属性。在并发过程中,内存的读写操作是互斥的,在写操作同时,读操作被阻塞,直到写操作完成之后,读操作才会执行。
因此上述例程中,循环过程中3个goroutine函数中读取v
数据的代码一直被阻塞。当循环体结束之后,读取操作才会继续。而此时v
的值是"c",因此3个goroutine读取出来的v
都是"c"。
如果我们想要得到输出结果:
a b c
需要对代码作出修改,对闭包goroutine函数加上一个形参:
for _, v := range []string{"a", "b", "c"} {
go func(v string) {
fmt.Println(v)
}(v)
}
这是因为编译器会为每个形参都都分配一个单独的内存空间,在外面实参传递进来的时候,实参数据被复制给形参,而这个动作是在外部循环的进程(或者说协程)上完成,因此不存在读写互斥的问题。
数据被复制给形参之后,3个goroutine读取到单独的内存数据,分别是"a","b","c"。从而输出我们预期的结果。
以上是关于go语言例程:并发中的型参的主要内容,如果未能解决你的问题,请参考以下文章