跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • golang 多个协程中 读取同一个 channel,怎么不是按顺序打印
未分類
6 2 月 2021

golang 多个协程中 读取同一个 channel,怎么不是按顺序打印

golang 多个协程中 读取同一个 channel,怎么不是按顺序打印

資深大佬 : hyp1002950 5

func main(){

ch := make(chan int)  go func(){  for{   c :=<-ch   fmt.Println("one:",c,"len:",len(ch))  } }()  go func(){  for{   c :=<-ch   fmt.Println("two:",c,"len:",len(ch))  } }()  for i:=1;i<=100;i++{  ch<-i }  time.Sleep(time.Second * time.Duration(2)) 

}

大佬有話說 (31)

  • 資深大佬 : cloverzrg2

    你把工作分给两个工人去做,工人 1 和工人 2 的完成的先后顺序是不确定的

  • 資深大佬 : jazzychai

    因为它们是 X 个 goroutine 在执行

  • 資深大佬 : huobazi

    按顺序用协程干啥?

  • 資深大佬 : beidounanxizi

    读取 channel 的数据顺序是顺序读取的
    但是你的 goroutine 运行顺序
    由调度器调度的 不受你的控制
    除非你能做到同步

  • 主 資深大佬 : hyp1002950

    <-ch 不是会阻塞么,我想着它应该是在协程中接收到 1 打印出来了 然后才能接收到 2 再打印,现在给我感觉是 接收和打印不是一个原子操作

  • 資深大佬 : yzbythesea

    先接受不一定先打印啊

  • 資深大佬 : yzbythesea

    必然不是原子啊

  • 資深大佬 : cxh116

    无脑猜 stdout print 应该算是 IO 操作, IO 操作时 goroutine 切换了.

  • 資深大佬 : zxlzy

    ch<-i 后面 sleep 一下

  • 主 資深大佬 : hyp1002950

    @cxh116 我觉得这个说法能想通,接收和打印应该是一起运行了,只是 print 是 IO 操作

  • 主 資深大佬 : hyp1002950

    @zxlzy 我在 fmt.Println 之后 sleep 了,打印就 1-100 了

  • 資深大佬 : sadfQED2

    你给你的管道缓冲长度设置成 1 就是顺序的了

  • 資深大佬 : sadfQED2

    你没设置长度,所以 ch<-i 不会阻塞

  • 資深大佬 : towry

    不能看不注重代码格式的人写的代码

  • 資深大佬 : no1xsyzy

    @sadfQED2 https://play.golang.org/p/zoNa2QRR6F- 然而不是……
    没设置长度的话我记得是没接收方就阻塞,有接收方转移到接收方
    而且就算设置长度输出仍然是混乱的

    似乎每个 goroutine 有单独的输出缓冲区,再用一个 channel 去集中的话就可以
    https://play.golang.org/p/Xa-lwecfveV
    但不是很懂没设置长度但有集中的情况下为什么还是乱的。

  • 資深大佬 : no1xsyzy

    @no1xsyzy 可能不是单独缓冲区一说,用令牌方法保证两个 goroutine 交替运行以后立即保证了输出也是 one two 交替的……
    而且 Println 应当会 flush ?

  • 資深大佬 : oluoluo

    这里的 channel 是无缓冲通道,会阻塞的,所以值是按照顺序从 channel 中取出来的,但是取值和打印不是原子的,中间调度器发生调度导致打印的结果不是顺序的。

  • 資深大佬 : janxin

    因为你 goroutine 调度不是顺序执行的

  • 資深大佬 : qq1340691923

    package main

    import (
    “fmt”
    “sync”
    “time”
    )

    func main() {
    loca := sync.Mutex{}
    ch := make(chan int)

    go func() {
    for {
    loca.Lock()
    {
    c := <-ch
    fmt.Println(“one:”, c, “len:”, len(ch))
    }
    loca.Unlock()

    }
    }()

    go func() {
    for {
    loca.Lock()
    {
    c := <-ch
    fmt.Println(“two:”, c, “len:”, len(ch))
    }
    loca.Unlock()
    }
    }()

    for i := 1; i <= 100; i++ {
    ch <- i
    }

    time.Sleep(time.Second * time.Duration(2))
    }

    这样就好了

  • 資深大佬 : php01

    接收到的顺序必然是按顺序来的,但是哪个协程先读到,或先写出,是控制不了的

  • 資深大佬 : Nitroethane

    @hyp1002950 #11 用 sleep 并不是完美的同步方法,虽然将 sleep 的时间设置的长一点可以在很大程度上得到顺序输出,但本质上由于 goroutine 调度器的原因还是会可能出现乱序输出情况,因为哪个 goroutine 先执行取决于调度器。正确的做法是用一个无 buffer 的 channel 去做两个 goroutine 之间的同步

  • 資深大佬 : keepeye

    用单核 cpu 可能得到顺序结果吧

  • 資深大佬 : kele1997

    “`
    var lock1 sync.Mutex
    var lock2 sync.Mutex

    func main() {
    ch := make(chan int)

    lock2.Lock()
    go func() {
    for {
    lock1.Lock()
    c := <-ch
    fmt.Println(“one:”, c, “len:”, len(ch))
    lock2.Unlock()
    }
    }()

    go func() {
    for {
    lock2.Lock()
    c := <-ch
    fmt.Println(“two:”, c, “len:”, len(ch))
    lock1.Unlock()
    }
    }()

    for i := 1; i <= 100; i++ {
    ch <- i
    }

    time.Sleep(time.Second * time.Duration(2))
    }

    “`

  • 資深大佬 : KaynW

    @keepeye 并不会

  • 資深大佬 : back0893

    协程的调用你没有办法保证是顺序调用

  • 資深大佬 : zhyl

    两个人在窗口取餐,谁先谁后肯定要争一争了。

  • 資深大佬 : Takamine

    channel 只是顺序放在了一个 queue 里,多个 worker 每次谁去取不一定。

  • 資深大佬 : useben

    底层是锁

  • 資深大佬 : kifile

    为什么绿皮车比高铁发车早,但是比高铁到的晚呢,这就是原因

  • 資深大佬 : zhuzeitou

    可以试试 go func 的最后 runtime.Gosched()一下

  • 資深大佬 : adamwong

    接收是原子的,接收+打印不是

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具