在goroutine 写入channel,为何还要在goroutine关闭才能遍历

delaywu · 2021-10-14 17:09:35 · 1345 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2021-10-14 17:09:35 的主题,其中的信息可能已经有所发展或是发生改变。

package main

import (
    "fmt"
    "sync"
)

func main() {
    wg := sync.WaitGroup{}

    var ret = make(chan int) 
    for i := 0; i < 100; i++ {
        wg.Add(1)
        go func(i int) {
            ret <- i
            wg.Done()
        }(i)
    }

    go func() {
        defer close(ret)
        wg.Wait()
    }()

    fmt.Println("执行结束")

    for v := range ret {
        fmt.Println(v)
    }
}

上段代码中

go func() {
        defer close(ret)
        wg.Wait()
    }()

为什么不能替换成:

wg.Wait()
close(ret)

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1345 次点击  ∙  1 赞  
加入收藏 微博
6 回复  |  直到 2021-10-19 23:13:10
delaywu
delaywu · #1 · 3年之前

我自己想应该是使用

wg.Wait()
close(ret)

阻碍的主线程,但是同时遍历是发生在主线程上。这时候定义的channel是无缓存的,这时候没办法发现这个无缓冲的channel又被消费的可能,故而会发生异常。这时候使用 协程的话,由于不堵塞。使得 channel消费成为的可能。

go func() {
        defer close(ret)
        wg.Wait()
    }()
fenglangjuxu
fenglangjuxu · #2 · 3年之前

关注

zzustu
zzustu · #3 · 3年之前

啥也不是,就是基础没学好

fenglangjuxu
fenglangjuxu · #4 · 3年之前

我大概知道 为什么了

wg.wait是阻塞的 是需要等待上面 100个阻塞的 goroutine 执行完成之后 才能继续往下执行

但是这100个 goroutine 可以完成的前提是 ret 这个chanel的数据 呗读取 就是需要下面的 range 来执行 才可以 让这goroutine 完成

但是 wg.wait 阻塞了 就没法继续往下执行下去

Amoteamame
Amoteamame · #5 · 3年之前
fenglangjuxufenglangjuxu #4 回复

我大概知道 为什么了 wg.wait是阻塞的 是需要等待上面 100个阻塞的 goroutine 执行完成之后 才能继续往下执行 但是这100个 goroutine 可以完成的前提是 ret 这个chanel的数据 呗读取 就是需要下面的 range 来执行 才可以 让这goroutine 完成 但是 wg.wait 阻塞了 就没法继续往下执行下去

不是,是当执行完100个goroutine后,ret没有被关闭,所以在下面的range ret中持续阻塞式接收数据,就没法继续往下执行下去。 所以需要再开一个goroutine,去等待所有goroutine结束后关闭channel。

__Golang__
__Golang__ · #6 · 3年之前

你这样搞的话,Wait得等到ret写100个后退出同步,ret得等到range准备好后才能写入,range得等到Wait退出同步才能执行,死锁

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传