golang中sync.WorkGroup的问题
本人go的小白一个,在gopl中看到的一段代码,有些地方心里有不是特别明白,贴出请教一下大家
func makeThumbnails6(filenames <-chan string) int64 {
sizes := make(chan int64)
var wg sync.WaitGroup // number of working goroutines
for f := range filenames {
wg.Add(1)
// worker
go func(f string) {
defer wg.Done()
thumb, err := thumbnail.ImageFile(f)
if err != nil {
log.Println(err)
return
}
info, _ := os.Stat(thumb) // OK to ignore error
sizes <- info.Size()
}(f)
}
// closer
go func() {
wg.Wait()
close(sizes)
}()
var total int64
for size := range sizes {
total += size
}
return total
}
thumbnail.ImageFile的具体内容不用关心,其原型如下
ImageFile(f string) (n string, e error)
closer那个goroutine,如果写在mainroutine中是会出错的,执行后报的是死锁的错。自己有点想法但是不太肯定,先说下自己的想法:
因为如果不在另一个goroutine中执行的话执行到wg.Wait()时就一直阻塞了main,因为没有接收channel的代码会执行(被Wait阻塞,后面的接收循环无法执行),所以除了第一个完成的goroutine所有的workerroutine都会被阻塞,造成死锁。
书中后面又说如果放在循环后面那么就不可达到,个人觉得是因为没有close,接收的循环就不会终止,只是会最后不断的接收到空值。
本人对并发不太懂,是做前端的,想自己学习一点后端,所以没有接触过正经的并发编程,请大家给我讲一讲吧!谢谢大家
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
![扫码二维码加入Web技术交流群](/public/img/jiaqun_03.jpg)
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我说说我的理解。。
主方法入参为channel,然后使用了sync.waitgroup来确保关闭sizes的队列关闭时从filenames过来的数据全部处理成功
filenames啥时候关闭?要是不关闭连第一个for都过不了就堵塞了吧。
处理完一条数据后wg.add和wg.done运行数量都为1,这时wg.wait就会过掉走close(sizes)这个时候在处理第二条数据,sizes <- info.Size()就会有问题吧,因为sizes已经关闭了。
假如说filenames写入N条数据后关闭。
第一个for接收到filenames的第一个消息后运行结束,在第二条数据还没来之前,wg.add和wg.done运行数量都为1,这时wg.wait就会过掉走close(sizes)这个时候在处理第二条数据,sizes <- info.Size()就会有问题吧。
假如只写入一条数据关闭
和
这两段代码的执行先后顺序是不一定的,能确定的是sizes <- info.Size()比defer wg.Done()早,
之后的是并发的话,所以这两段代码先后顺序就不是固定的了。
有可能会先执行了close(sizes)再运行for,这样子也会报错吧
sizes无缓存写和读都会阻塞,woker写sizes阻塞
wg.wait也会阻塞
代码解析:
(1) filenames发送channel,只能进行读操作,不能用close关闭写权限
(2) 这里sizes为无缓存双向channel,所以只有调用close,sizes的range循环才能结束掉
(3) 所以wg.wait如果放在main goroutine range size之前 则由于sizes读取堵塞,wg.done()不执行,则wg.wait会一直堵塞下去
(4) 所以wg.wait如果放在main goroutine range size之后 则没有调用close sizes,则sizes一直range循环不停止