Skip to content

Wrong Code Example for Mistake 64 (Expecting a deterministic behavior using select and channels) #134

@gatogato999

Description

@gatogato999

Describe the mistake

In the description of "Expecting a deterministic behavior using select and channels (64)" , its written that the output of the code will be random :

0
1
2
disconnection, return
# or 
0
disconnection, return
  • But here, that situation doesn't arise because the disconnect send happens strictly after all message sends.
  • the true output is not random , its always :
0
1
2
3
4
5
6
7
8
9
disconnection, return
  • you will see the numbers 0–9 printed (in order), then "disconnection, return", and the program exits.
  • the code snippet shows a goroutine that does two things in sequence:
  1. Sends integers 0 through 9 into messageCh
  2. After the loop finishes, sends a signal into disconnectCh

Meanwhile, the main loop continuously runs a select with two cases:

  1. receive from messageCh
  2. receive from disconnectCh
  3. Key detail: ordering guarantee
  • Inside the goroutine, this part is strictly sequential:
  1. All messageCh <- i sends happen first
  2. Only after the loop completes does disconnectCh <- struct{}{} run

So the disconnect signal cannot happen before all numbers are sent.

  • What the select does
  1. Pick messageCh whenever a value is available
  2. Eventually pick disconnectCh once that signal is sent

Because the disconnect happens after all sends, the loop will first consume all numbers.

Solution

Make the output non-deterministic

  • Right now, the code is deterministic because:
  1. One goroutine sends values in order
  2. disconnectCh only fires after all sends finish
  • To make it “random”, you need multiple competing producers or race between channels.
  • Example: multiple goroutines sending
for i := 0; i < 10; i++ {
    go func(n int) {
        messageCh <- n
    }(i)
}

go func() {
    // give time for sends to race
    time.Sleep(time.Millisecond * 10)
    disconnectCh <- struct{}{}
}()

for {
    select {
    case v := <-messageCh:
        fmt.Println(v)
    case <-disconnectCh:
        fmt.Println("disconnection, return")
        return
    }
}

What changes?

  • Now 10 goroutines are sending concurrently
  • Order becomes non-deterministic

Metadata

Metadata

Assignees

No one assigned

    Labels

    community mistakeMistakes proposed by the community

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions