duanpin5168 2018-05-08 16:33
浏览 138
已采纳

Golang多通道写入/接收排序

My specific issue is that I have an unbuffered channel and am spawning multiple goroutines bounded with a semaphore to perform work:

func main() {
    sem := make(chan struct{}, 10) // allow ten concurrent parsers
    wg := &sync.WaitGroup{}
    wg.Add(1)
    DoSomething("http://example.com", sem, wg)

    wg.Wait()
    // all done
}

func DoSomething(u string, sem chan struct{}, wg *sync.WaitGroup) {
    defer wg.Done()

    sem <- struct{}{}        // grab
    defer func() { <-sem }() // release


    var newSomethings []string

    // ...

    for u := range newSomethings {
        wg.Add(1)
        go DoSomething(u)
    }
}

If there are multiple DoSomething goroutines on the stack, blocked on the sem write (or inversely on a read) When a write happens is there any ordering to which go routine gets through with the write?? I would guess it were random but I could imagine:

  • it is random
  • writes/receives happen in the order they are registered
  • implementation dependent

I looked at a couple of resources and was unable to find a solution:

I'm wondering if this is undefined and/or implementation dependent, or if this logic is located and defined somewhere within go core?

  • 写回答

1条回答 默认 最新

  • dongtiao2105 2018-05-08 18:32
    关注

    The order that goroutines blocked on a send operation are serviced is not defined, but it's implemented as a FIFO. You can see the implementation in runtime/chan.go, which uses a linked list to track the channel's senders and receivers.

    We can try to make an example showing the effective ordering like so:

    func main() {
        ch := make(chan int)
        ready := make(chan int)
    
        for i := 0; i < 10; i++ {
            i := i
            go func() {
                ready <- 1
                ch <- i
            }()
            <-ready
            runtime.Gosched()
        }
    
        for i := 0; i < 10; i++ {
            v := <-ch
            if i != v {
                panic("out of order!")
            }
            fmt.Println(v)
        }
    }
    

    https://play.golang.org/p/u0ukR-5Ptw4

    This still isn't technically correct, because there's no way to observe blocking on a send operation, so there's still a race between the ready send and the send to ch on the next line. We can try to eliminate that with the runtime.Gosched call here, or even a time.Sleep, but without explicit synchronization there's no guarantee of a "happens before" relationship.

    Regardless, this queues up the goroutines and shows the expected output order, and if they weren't queued up already, it would be more likely to process the values out of order.

    You can see by this example that we can't truly determine the order that the goroutines are queued up, it is almost always non-deterministic, and therefore reasoning about this isn't usually useful in practice.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么
  • ¥15 banner广告展示设置多少时间不怎么会消耗用户价值
  • ¥16 mybatis的代理对象无法通过@Autowired装填
  • ¥15 可见光定位matlab仿真
  • ¥15 arduino 四自由度机械臂
  • ¥15 wordpress 产品图片 GIF 没法显示
  • ¥15 求三国群英传pl国战时间的修改方法
  • ¥15 matlab代码代写,需写出详细代码,代价私
  • ¥15 ROS系统搭建请教(跨境电商用途)
  • ¥15 AIC3204的示例代码有吗,想用AIC3204测量血氧,找不到相关的代码。