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:
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?
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.