Question

I am having very strange behavior in my Go code. The overall gist is that when I have

for {
  if messagesRecieved == l {
    break
  }
  select {
  case result := <-results:
    newWords[result.index] = result.word
    messagesRecieved += 1
  default:
    // fmt.Printf("messagesRecieved: %v\n", messagesRecieved)
    if i != l {
      request := Request{word: words[i], index: i, thesaurus_word: results}
      requests <- request
      i += 1
    }
  }
}

the program freezes and fails to advance, but when I uncomment out the fmt.Printf command, then the program works fine. You can see the entire code here. does anyone know what's causing this behavior?

Was it helpful?

Solution

Go in version 1.1.2 (the current release) has still only the original (since initial release) cooperative scheduling of goroutines. The compiler improves the behavior by inserting scheduling points. Inferred from the memory model they are next to channel operations. Additionaly also in some well known, but intentionally undocumented places, such as where I/O occurs. The last explains why uncommenting fmt.Printf changes the behavior of your program. And, BTW, the Go tip version now sports a preemptive scheduler.

Your code keeps one of your goroutines busy going through the default select case. As there are no other scheduling points w/o the print, no other goroutine has a chance to make progress (assuming default GOMAXPROCS=1).

I recommend to rewrite the logic of the program in a way which avoids spinning (busy waiting). One possible approach is to use a channel send in the default case. As a perhaps nice side effect of using a buffered channel for that, one gets a simple limiter from that for free.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top