Go圣经-学习笔记之并发循环


声明:本文转载自https://my.oschina.net/u/3287304/blog/1557766,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

上一篇 Go圣经-学习笔记之error接口

下一篇 Go圣经-学习笔记之select多路复用

首先说一个,本来上一篇文章应该是, Go圣经-学习笔记之Channel和Goroutine。写了很长一段,结果被有道云笔记TMD坑惨了,服务掉了,不能拷贝,不能保存。这篇文章就丢了。如果以后有时间,我再补,最近比较忙,先把后面部分写完。

并发循环

func main() {     var count = 10     var mg = make(chan struct{}, count)     for i := 0; i < count; i++ {         go func() {             fmt.Printf("i=%d\n", i+1)             mg <- struct{}{}         }()     }     for i := 0; i < count; i++ {         <-mg     }     close(mg)     return } 

在Go圣经-学习笔记之函数值那篇文章中,可以知道函数值是由函数体和引用环境构成的。所以上面的返回结果是在GoSched调用Goroutine后运行时的引用变量,所以这个打印值是不确定的,但是一般来说结果是11。在以后写雨痕老师的学习笔记时,我再来具体讲解。Go f()只是创建一个goroutine,只有Goroutine被GoSched调度后才能真实的运行在内核态,这个时候获取变量i时,就是这时内存i变量值。这里for循环运行结束后,10个goroutine还没来得及被调度,所以i值都是11。

func main() {     var count = 10     var mg = make(chan struct{}, count)     for i := 0; i < count; i++ {         go func() {             fmt.Printf("i=%d\n", i+1)             mg <- struct{}{}         }()         time.Sleep(3 * time.Second)  // main goroutine sleep 3s     }     for i := 0; i < count; i++ {         <-mg     }     close(mg)     return } 

每执行一次for循环,main goroutine休息3s,则其他goroutine肯定会被GoSched调度,所以这个时候,打印值分别是:1,2,3,4,..., 10

改进一

如果你不想把变量i放在引用环境中,另一种方法

func main() {     var count = 10     var mg = make(chan struct{}, count)     for i := 0; i < count; i++ {         go func(i int) {             fmt.Printf("i=%d\n", i+1)             mg <- struct{}{}         }(i)     }     for i := 0; i < count; i++ {         <-mg     }     close(mg)     return } 

改进二

如果goroutine执行过程中发生了错误,需要把错误信息汇总到一个指定的goroutine,可以使用channel来实现。

func main() {     var (         count = 10         errs = make(chan error, count)         wg =new(sync.WaitGroup)     )     wg.Add(count)     go processErrors(errs)     for i := 0; i < count; i++ {         go func(i int, errs chan err) {             wg.Done()             err := fmt.Errorf("error %d.", i+1)             errs<-err         }(i, errs)     }     wg.Wait()     close(errs)     return }  func processErrors(errs <-chan error) {     for err := range errs{         fmt.Println(err.Error())     }     return } 

这里要说明的一点是:channel的两端发送者和接受者goroutine都不能一直阻塞下去,如果一直阻塞那就是goroutine泄露。

本文发表于2017年10月29日 12:34
(c)注:本文转载自https://my.oschina.net/u/3287304/blog/1557766,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 2101 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1