Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Comments on Message receive and wait channel misleading #4

Open
WhisperingChaos opened this issue Apr 17, 2021 · 2 comments
Open

Comments on Message receive and wait channel misleading #4

WhisperingChaos opened this issue Apr 17, 2021 · 2 comments

Comments

@WhisperingChaos
Copy link

Certain comments in the sequencing pattern imply Joe's goroutine will generate the first received Message struct followed by Ann's:

msg1 := <-c // Waiting on someone (Joe) to talk
fmt.Println(msg1.str)
msg2 := <-c // Waiting on someone (Ann) to talk
fmt.Println(msg2.str)
msg1.wait <- true // Joe can run again
msg2.wait <- true // Ann can run again

However, the code doesn't explicitly define a Happens Before dependency to ensure this ordering. Therefore, it's possible that Ann's Message struct will precede Joe's resulting in the variable msg1 containing Ann's message, not Joe's as suggested by the comments.

If a strict Round-robin ordering is desired, the following implementation delivers the same outcome while eliminating the wait abstraction and its associated code.

@ardan-bkennedy
Copy link
Member

Yes, this is concurrent code (out of order execution) so the goroutine started for Ann could execute before Joe. However, the code you listed in Main is running on it's on goroutine and is sequential. What we see is the order of execution for that goroutine and if Ann executes first underneath, it won't change the output of main.

@WhisperingChaos
Copy link
Author

Yes, this is concurrent code (out of order execution) so the goroutine started for Ann could execute before Joe.

Agreed.

However, the code you listed in Main is running on it's on goroutine and is sequential.

Agreed.

Given the fanIn function code:

go func() { // This Goroutine will receive messages from Joe.
for {
c <- <-input1 // Write the message to the FanIn channel, Blocking Call.
}
}()
go func() { // This Goroutine will receive messages from Ann.
for {
c <- <-input2 // Write the message to the FanIn channel, Blocking Call.
}
}()

  • Does not directly cause these goroutines to execute,
  • and there isn't any code within them nor code external to them that orders/coordinates their initial execution.

Therefore, even though main is sequentially executing its loop, it's left to the golang runtime scheduler to determine the execution order of the (concurrent) goroutines that that feed Message(s) to the common channel referenced by main. Since the runtime scheduler doesn't, by itself, guarantee the execution ordering of goroutines, the output of the sequential loop can change. That is, the first Message from Ann can appear before Joe's first one.

Finally, the evidence of this behavior in a running example. A trivial change that reduces the scope of the variable waitForIt in the function boring shouldn't affect the ordering of the output messages. However, it does. Please run the following playground code a few times to witness the "Ann 0" message output before "Joe 0".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants