Last active
April 18, 2018 00:49
-
-
Save WhisperingChaos/905056e7b29fc4b498d10122919a035e to your computer and use it in GitHub Desktop.
Exploring implicit goroutine ordering and selection from queue.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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