| Q: can you reopen a channel? (e.g. when using close() as a barrier) | Jason E. Aten | 06/05/14 17:33 | I'm reflecting on John Graham-Cumming's Channel Compendium talk at GopherCon: Specifically, where he suggests using channel close() as a barrier synchronization method. // example from slide 10 of https://github.com/gophercon/2014-talks/blob/master/John_Graham-Cumming_A_Channel_Compendium.pdf func worker(start chan bool) { <- start // ... do stuff } func main() { start := make(chan bool) for i := 0; i < 100; i++ {" go worker(start)" } close(start) // ... all workers running now (line 12) } First a quick observation: there's no *guarantee* that all (or even any) of the workers have running by the the time (line 12) is encountered right? It is non-deterministic is it not? I thought that, for the moment assuming without loss of generality that we are on a single thread, that execution could proceed straight on past the close(), so actually I *don't* know that all workers are running by line 12, right? Then on to my question: Q: If close() is a reasonable way to implement barrier synchronization, I wondered about how to reset such a barrier; i.e. can I re-open a channel? Of course I could over-write a global channel variable with a reference to a new open channel, but I have no guarantee that the write to a global channel would be atomic, right? (i.e. if the global variable reference was multiple words, could it ever be read in a half-written state)? If not, it doesn't seem like close() makes for a very good barrier after all. Thanks. Jason |
| Re: [go-nuts] Q: can you reopen a channel? (e.g. when using close() as a barrier) | Jesse McNelis | 06/05/14 17:51 | On Wed, May 7, 2014 at 10:33 AM, Jason E. Aten <j.e....@gmail.com> wrote:From the perspective of the goroutine running main() all the goroutines are running. It doesn't matter if they are running from their own perspectives. If main() wants to communicate with those goroutines then it will have to do some kind of synchronisation and wait for them to catch up. You can't re-open a channel, that would be lying. Yes, you can't 'reset' the barrier. So you'd have a different solution if that was a requirement. Not if you need to reset it. |
| Re: [go-nuts] Q: can you reopen a channel? (e.g. when using close() as a barrier) | Rui Ueyama | 06/05/14 18:25 | You can create a new channel and assign it to a global variable, yes. However, other goroutines may continue observing the old value because the Go memory model does not guarantee such thing. http://golang.org/ref/mem
You need some synchronization mechanism, like a channel, mutex, WaitGroup, etc, to update and share the global variable. But if you have such object, you could use it as a barrier in the first place.
So, reassigning to the global variable is a strategy that won't work. -- |
| Re: [go-nuts] Q: can you reopen a channel? (e.g. when using close() as a barrier) | Jason E. Aten | 06/05/14 18:45 | Thanks, Jesse. I discovered sync.WaitGroup() and that does seem to be the idiomatic way to do barriers. |
| Re: [go-nuts] Q: can you reopen a channel? (e.g. when using close() as a barrier) | Dmitry Vyukov | 06/05/14 23:33 | On Wed, May 7, 2014 at 4:33 AM, Jason E. Aten <j.e....@gmail.com> wrote:Correct If somebody is reading the global variable concurrently with the write, then you are already in trouble, because it can read the reference to the old channel and block on it forever. If nobody is reading the variable, then there is no need to make it atomic.
|
| Re: [go-nuts] Q: can you reopen a channel? (e.g. when using close() as a barrier) | Jason E. Aten | 08/05/14 03:46 | Just wanted to follow up that I started to understand why folks would recommended closing a channel over using a WaitGroup; a WaitGroup doesn't have a channel you can use in a select {}. The conceptual addition that I needed to get "WaitGroup" like outcome was to add a 2nd channel in addition to done. I called it ackdone in this example, to communicate back to the supervisor that the done was acknowledged. For example: Then I just have to think in terms of allocating new channels for done and ackdone on each fan-out, and it should work fine to use close(done) on a channel done to indicate shutdown.http://play.golang.org/p/k0Qs0ZOSfF As a side effect of implementing a circle/ring/chain, I'm able to measure send/receive overhead. The circle.go code in the playground reference about shows me that the overhead to send and receive an integer between two goroutines (even using a buffer) on my linux/x86_64 box using go 1.2.1 is about 380 microseconds. This seems really expensive. Does this match anyone's expectations? Thanks, Jason -- |
| Re: [go-nuts] Q: can you reopen a channel? (e.g. when using close() as a barrier) | Dmitry Vyukov | 08/05/14 04:02 | $ go test -run=run -bench=BenchmarkChanProdCons100 runtime
BenchmarkChanProdCons100 50000000 60.1 ns/op > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an |