问答。上一节有读者问goroutinestacksize有多大。详细查询了官方文档中的goroutinestacksize(栈内存大小)。在1.2之前是最小的。原来是4kb,1.2变成8kb,最大栈大小可以用SetMaxStack设置。运行时/调试包可以控制最大单个goroutine堆栈的大小。在64位系统上默认为1GB,在32位系统上默认为250MB。因为每个goroutine都需要能够运行,所以他们有自己的栈。如果每个goroutine分配一个固定的stacksize,不能增长,太小会造成overflow,太大会浪费空间,而且goroutine不能多。所以在1.3版本中,改为Contiguousstack(连续栈)。为了解决这个问题,goroutine一开始只能给栈分配一小块空间(8KB),然后在使用过程中根据需要自动增长。这就是为什么Go可以启动数千个goroutine而不会耗尽内存的原因。1.4版本goroutine栈从8Kb缩减到2Kb本节Golang并发等待源码位置https://github.com/golang-minibear2333/golang/blob/master/4.concurrent/goroutine-wait/》介绍goroutine非常有用GolangFunction,有时候goroutine在函数执行完之前就返回了,想等当前goroutine执行完再继续怎么办funcsay(sstring){fori:=0;i<3;i++{time.sleep(100*time.Millisecond)fmt.Println(s)}}funcmain(){gosay("helloworld")fmt.Println("over!")}输出结束!,主线程不等待使用Sleep等待forfuncmain(){gosay("helloworld")time.Sleep(time.Second*1)fmt.Println("over!")}运行修改后的程序,结果如下:helloworldhelloworldhelloworldover!结果符合预期,但太低了,我们不知道实际执行时应该等待多长时间,所以这个解决方案是不可接受的!发送信号funcmain(){done:=make(chanbool)gofunc(){fori:=0;i<3;我++{time.Sleep(100*time.Millisecond)fmt.Println("helloworld")}done<-true}()<-donefmt.Println("over!")}输出结果同上,也符合预期。此方法无法处理多个协程。所以这不是一个优雅的解决方案。WaitGroupGolang官方在sync包中提供了WaitGroup类型来解决这个问题。其文档描述如下:使用方法可以归纳为以下几点:在父协程中创建一个WaitGroup实例,例如名称为:wg调用wg.Add(n),其中n为协程的个数waitinggoroutinestorun在每个goroutine中执行deferwg.Done()函数中调用wg.Wait()阻塞主逻辑,直到所有goroutine执行完毕。funcmain(){varwgsync.WaitGroupwg.Add(2)gosay2("hello",&wg)gosay2("world",&wg)fmt.Println("over!")wg.Wait()}funcsay2(sstring,waitGroup*sync.WaitGroup){deferwaitGroup.Done()fori:=0;i<3;i++{fmt.Println(s)}}输出,注意并发执行导致顺序乱了hellohellohelloover!该变量被一个中间变量替换以防止关闭){deferwg.Done()fmt.Println(d)}()}wg.Wait()}输出,可以发现最后bb的所有父协程和子协程都是并发的。父协程上的for循环瞬间执行,内部协程使用d的最后一个值,这就是闭包问题。解决方案作为参数传递给funccorrectFunc(){varwgsync.WaitGroupsList:=[]string{"a","b"}wg.Add(len(sList))for_,d:=rangesList{gofunc(strstring){deferwg.Done()fmt.Println(str)}(d)}wg.Wait()}输出ba要注意1.7.3中可能遇到的坑在取值范围内!
