Skip to content

Instantly share code, notes, and snippets.

@WhisperingChaos
Last active April 18, 2018 00:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save WhisperingChaos/905056e7b29fc4b498d10122919a035e to your computer and use it in GitHub Desktop.
Save WhisperingChaos/905056e7b29fc4b498d10122919a035e to your computer and use it in GitHub Desktop.
Exploring implicit goroutine ordering and selection from queue.
package main
/*
Exploring goroutine ordering imposed by runtime scheduling. The
situation encoded below consists of a single synchronous writer and two
concurrent readers. The readers are connected to the writer via a single
unbuffered shared channel. A
selection of "next" goroutine from runtime scheduling queue. Trying
to enforce "fairness" whose meaning in this situation guarantees execution
of all goroutines, avoiding goroutine starvation/barging explained
here: https://github.com/golang/go/issues/11506.
go PlayGound: https://play.golang.org/p/4sGKDepzqaV
*/
import (
"fmt"
"time"
)
func main() {
read := make(chan bool)
term := make(chan bool)
start := make(chan bool)
go reader(read, start, term, "1")
/*
start <-true below:
- Forces first reader goroutine labeled "Reader: 1" to start executing.
- "Reader: 1" blocks waiting to receive on "read" channel.
- Due to this block, establishes a HA relationship to sending
goroutine "main()" whose "for" loop issues channel send.
*/
start <-true
go reader(read, start, term, "2")
/*
start <- true below:
- Forces start of "Reader:2"
- Behaves the same as "Reader: 1".
- Due to sequential nature of this goroutine, "main()", "Reader 2" exists
in an explicit HA relationship with "Reader 1".
*/
start <-true
/*
Before starting the "for" loop below:
- "Reader: 1" is blocked on its "for range" statement.
- "Reader: 2" is blocked on its "for range" statement.
- "Reader: 1" must be the first goroutine in blocked queue. Due to its HA
relationship with "main()" and its currently explicit HB relationship
with Reader 2".
- "Reader: 2" must be the second goroutine in blocked queue. Due to its HA
relationship with "main()" and its once explicit HA relationship
with Reader 1".
*/
for i := 0; i < 100; i++ {
time.Sleep(0 * time.Nanosecond)
read <- true
}
close(read)
<-term
<-term
}
/*
"reader()" notes:
- All readers use the same function below.
- Using an identically encoded function reduces differences in
in a function's execution speed to only environment concerns.
- No explicit HB relationship between readers is enforced by
this function.
- Removing the fmt.Printf from the "for range" loop will further
reduce environment factors that affect the function's execution
speed thereby encourage little variation in function's duration
when processing a read request.
*/
func reader(read <-chan bool, start <-chan bool, term <-chan bool, tag string) {
var tot int
<-start
for range read {
tot++
fmt.Printf("Reader: %s\n", tag)
}
fmt.Printf("Reader: %s Total: %d\n", tag, tot)
term <- true
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment