gpt4 book ai didi

Golang 多 channel 写/接收排序

转载 作者:IT王子 更新时间:2023-10-29 01:57:04 25 4
gpt4 key购买 nike

我的具体问题是我有一个无缓冲的 channel ,并且正在生成多个与信号量绑定(bind)的 goroutines 来执行工作:

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)
}
}

如果堆栈上有多个 DoSomething goroutine,在 sem 写入时被阻塞(或在读取时相反)例程通过写来完成??我猜它是随机的,但我可以想象:

  • 是随机的
  • 写入/接收按照它们被注册的顺序发生
  • 依赖实现

我查看了一些资源,但无法找到解决方案:

我想知道这是否是未定义的和/或依赖于实现的,或者这个逻辑是否位于并定义在 go 核心的某个地方?

最佳答案

在发送操作中阻塞的 goroutines 的服务顺序没有定义,但它是作为 FIFO 实现的。您可以在 runtime/chan.go 中查看实现,它使用链表来跟踪 channel 的发送者和接收者。

我们可以尝试做一个例子来展示有效的顺序:

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

这在技术上仍然不正确,因为无法观察发送操作的阻塞,所以 ready 发送和发送到 ch 之间仍然存在竞争> 在下一行。我们可以尝试通过此处的 runtime.Gosched 调用,甚至是 time.Sleep 来消除它,但如果没有显式同步,则无法保证 "happens before"。关系。

无论如何,这会将 goroutine 排队并显示预期的输出顺序,如果它们尚未排队,则更有可能乱序处理值。

通过这个例子可以看出,我们无法真正确定 goroutine 排队的顺序,它几乎总是不确定的,因此对此进行推理在实践中通常没有用。

关于Golang 多 channel 写/接收排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50238388/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com