Skip to content

Instantly share code, notes, and snippets.

@probablytom
Last active May 9, 2023 07:32
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 probablytom/e29dfdf0f2ea988b8c15a3a2e2c6eeb6 to your computer and use it in GitHub Desktop.
Save probablytom/e29dfdf0f2ea988b8c15a3a2e2c6eeb6 to your computer and use it in GitHub Desktop.
An experiment to see whether Golang channels evaluate the values to pass along a blocking channel before or after the blocking channel is called upon for a value by another routine.

This is an experiment to see how Go handles chaining channels together. If a channel is returning a value taken from a second channel, does it take the value from the second one when it stops blocking, or when it begins to block?

Say we have the (syntactically valid!) Go code:

x <- <- y

which passes a value from channel y onto a channel x.

Let's also say that channel y already has a value on it. We're interested in having someone eventually read from channel 'x', but controlling whatever value is on it from somewhere else. One use case for this might be a channel which blocks to put values onto, but returns a default value (populated by some goroutine) if the channel would otherwise be empty. This would give us a channel which would block feeding it new values, but would return a default value rather than blocking when reading from it if empty.

We're going to read from channel x, which is blocking. Before we do, we change the value on channel y.

If we get the updated value on y, then we know that the values served by the first value are taken from the second only after blocking. If not, it should reach a deadlock.

package main
import "time"
func main() {
// Variables we'll need
x := make(chan int)
y := make(chan int, 1)
// If chaining channels together will present old values rather than new ones, we'll see a deadlock instead of 6.
// That's because we're going to have two routines which remove a value from this channel, and we're interested to see
// which routine pulls from the channel first.
y <- 5
// A goroutine which takes a value from `y`, passes it onto `x`, and then exits.
// Because `x` is blocking, this will block until a values is *read* from `x`.
// Will we see the new value -- 6 -- or hit a deadlock?
go func() {
x <- <- y
}()
// Now -- after sleeping, just to be 100% certain the above routine is waiting -- we
// replace the value on channel `y`. Does `x` now serve the value 5, or the value 6?
time.Sleep(1000)
<-y
y <- 6
if 6 == <- x {
println("We take values after blocking, meaning when values on a blocking channel are requested from another routine.")
} else {
println("We take values before blocking, and those values then sit on the channel and wait to be sent.")
}
}
@rkojedzinszky
Copy link

Similar topic, when the value is evaluated?

package main

import (
	"fmt"
	"time"
)

func main() {
	bchan := make(chan bool)
	value := false

	go func() {
		bchan <- value
	}()

	time.Sleep(time.Second)

	value = true

	fmt.Println(<-bchan)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment