golang中sync.WorkGroup的问题

发布于 2022-09-04 04:57:16 字数 1253 浏览 18 评论 0

本人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技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

甜宝宝 2022-09-11 04:57:16

我说说我的理解。。
主方法入参为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()就会有问题吧。
假如只写入一条数据关闭

go func() {
        wg.Wait()
        close(sizes)
    }()

  var total int64
        for size := range sizes {
            total += size
        }
        return total
    

这两段代码的执行先后顺序是不一定的,能确定的是sizes <- info.Size()比defer wg.Done()早,
之后的是并发的话,所以这两段代码先后顺序就不是固定的了。
有可能会先执行了close(sizes)再运行for,这样子也会报错吧

暗喜 2022-09-11 04:57:16

sizes无缓存写和读都会阻塞,woker写sizes阻塞
wg.wait也会阻塞

那伤。 2022-09-11 04:57:16

代码解析:
(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循环不停止

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文