Порядок обслуживания блоков, заблокированных в операции отправки, не определен, но реализован как FIFO.Вы можете увидеть реализацию в runtime / chan.go , которая использует связанный список для отслеживания отправителей и получателей канала.
Мы можем попытаться сделать пример, показывающий эффективное упорядочение, вот так:
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
, но без явной синхронизации нет гарантии, что «произойдет до» отношения .
Независимо от того,это ставит в очередь программы и показывает ожидаемый порядок вывода, и если они еще не были поставлены в очередь, было бы более вероятно обработать значения не по порядку.
Из этого примера видно, что мы можемна самом деле не определяет порядок, в котором очереди помещаются в очередь, он почти всегда недетерминирован, и поэтому рассуждения об этом обычно бесполезны на практике.