求助求助 有关channel 单向通道(旧)和 无缓冲通道一直写入没有发生阻塞(新) 的问题

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

最近刚入门golang 学到了channel 自己仿照模板在main函数里写了一个单向通道的小demo 但是跑不出想要的效果 想请教各位大佬 帮我看看是哪个地方出现了问题

代码如下

    c := make(chan int)
    go func(out chan<- int) {
        fmt.Println("product func")
        mutex.Lock() //加锁保证对通道的占用
        for i:=0 ; i<= 5;i++{
            out <- i
        }
        mutex.Unlock()
        fmt.Println("product func end")
    }(c)

    go func(in <-chan int ) {
        fmt.Println("consumer function")
        for num := range in{
            fmt.Println(num)
        }
        fmt.Println("consumer function end")
    }(c) //把双向channel传入 单向channel作为参数的函数 中

运行结果啥也没有

1.png

--------------------------------分割线------------------------------------------

经过前两楼的大佬的指定 ,知道了之前的原因是main goroutine挂的太快 但是我结合3l大哥的回复想了一下,在自己的程序里 “无缓冲通道+锁” 按道理应该会造成 “写段阻塞”报错 但实际运行起来却没有问题,有老哥能帮忙分析一下是什么原因吗? 修改以后的代码

    c := make(chan int)
    go func(out chan<- int) {
        fmt.Println("product func")
        defer close(c)
        mutex.Lock() //加锁保证对通道的占用
        for i:=0 ; i<= 5;i++{
            out <- i
        }
        mutex.Unlock()
        fmt.Println("product func end")
    }(c)

    go func(in <-chan int ) {
        fmt.Println("consumer function")
        for num := range in{
            fmt.Println(num)
        }
        fmt.Println("consumer function end")
    }(c) //把双向channel传入 单向channel作为参数的函数 中

    time.Sleep(5*time.Second)
    /*
    主线程挂了之后,程序会直接退出,你启动的两个协程还没来得及运行,程序已经退出了。在最后面加个sleep 或者用sync.WaitGroup
    */

QQ截图20211027153711.png


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

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

1046 次点击  
加入收藏 微博
11 回复  |  直到 2021-10-28 09:03:24
xhatt
xhatt · #1 · 3年之前

主线程挂了之后,程序会直接退出,你启动的两个协程还没来得及运行,程序已经退出了。在最后面加个sleep 或者用sync.WaitGroup

dagongrenzzZ
dagongrenzzZ · #2 · 3年之前
xhattxhatt #1 回复

主线程挂了之后,程序会直接退出,你启动的两个协程还没来得及运行,程序已经退出了。在最后面加个sleep 或者用sync.WaitGroup

非缓冲通道,还加锁保证通道占用,先不谈运行结果:grinning:

a1al
a1al · #3 · 3年之前
xhattxhatt #1 回复

主线程挂了之后,程序会直接退出,你启动的两个协程还没来得及运行,程序已经退出了。在最后面加个sleep 或者用sync.WaitGroup

感谢~

a1al
a1al · #4 · 3年之前
dagongrenzzZdagongrenzzZ #2 回复

#1楼 @xhatt 非缓冲通道,还加锁保证通道占用,先不谈运行结果:grinning:

谢谢指正!

dagongrenzzZ
dagongrenzzZ · #5 · 3年之前
a1ala1al #4 回复

#2楼 @dagongrenzzZ 谢谢指正!

你没理解我的意思,这个锁可以加但没必要,你始终只有一个协程在写

xhatt
xhatt · #6 · 3年之前

改成这样,你才能让他阻塞,2个协程去抢同一把锁才会阻塞,你只有一个协程拿锁,不会阻塞的。

c := make(chan int)
    mutex := sync.Mutex{}
    go func(out chan<- int) {
        fmt.Println("product func")
        defer close(c)
        mutex.Lock() //加锁保证对通道的占用
        for i:=0 ; i<= 5;i++{
            out <- i
        }
        mutex.Unlock()
        fmt.Println("product func end")
    }(c)

    go func(in <-chan int ) {
        mutex.Lock() //加锁保证对通道的占用
        fmt.Println("consumer function")
        for num := range in{
            fmt.Println(num)
        }
        mutex.Unlock()
        fmt.Println("consumer function end")
    }(c) //把双向channel传入 单向channel作为参数的函数 中

    time.Sleep(5*time.Second)

这样你程序就只会打印

product func
consumer function

然后5秒自己退出

a1al
a1al · #7 · 3年之前
dagongrenzzZdagongrenzzZ #5 回复

#4楼 @a1al 你没理解我的意思,这个锁可以加但没必要,你始终只有一个协程在写

是的。 您的意思是锁是解决多个进程之间对同一个资源写和写的冲突。 我这里本来想着是 用锁实现一批数据的先写后读 但是没有考虑到缓冲的问题,在您提醒以后,我突然意识到了这一点。 但是我试着运行了一下又发现可以运行, 按道理,如果加了锁,我还往无缓冲chan里一直写,岂不是会造成 “ 写端的阻塞”

a1al
a1al · #8 · 3年之前
xhattxhatt #6 回复

改成这样,你才能让他阻塞,2个协程去抢同一把锁才会阻塞,你只有一个协程拿锁,不会阻塞的。 ``` go c := make(chan int) mutex := sync.Mutex{} go func(out chan<- int) { fmt.Println("product func") defer close(c) mutex.Lock() //加锁保证对通道的占用 for i:=0 ; i<= 5;i++{ out <- i } mutex.Unlock() fmt.Println("product func end") }(c) go func(in <-chan int ) { mutex.Lock() //加锁保证对通道的占用 fmt.Println("consumer function") for num := range in{ fmt.Println(num) } mutex.Unlock() fmt.Println("consumer function end") }(c) //把双向channel传入 单向channel作为参数的函数 中 time.Sleep(5*time.Second) ``` 这样你程序就只会打印 ``` product func consumer function ``` 然后5秒自己退出

膜拜膜拜! 确实如您所说一样,而且如果把无缓冲chan改成缓冲chan就能达到想要的效果!感谢您!

dagongrenzzZ
dagongrenzzZ · #9 · 3年之前
a1ala1al #7 回复

#5楼 @dagongrenzzZ 是的。 您的意思是锁是解决多个进程之间对同一个资源写和写的冲突。 我这里本来想着是 用锁实现一批数据的先写后读 但是没有考虑到缓冲的问题,在您提醒以后,我突然意识到了这一点。 但是我试着运行了一下又发现可以运行, 按道理,如果加了锁,我还往无缓冲chan里一直写,岂不是会造成 “ 写端的阻塞”

无缓冲其实就是阻塞通道。假如你往里写入1而不读取,就会一直阻塞,只有你读取了1,才能继续写入2,所以锁根本没有起作用

1034992601
1034992601 · #10 · 3年之前

channel 自身会有锁机制,不用额外加锁

a1al
a1al · #11 · 3年之前

@1034992601 谢谢老哥!

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