go - What is an elegant way to shut down a chain of goroutines linked by channels? -
i'm go learner. in order better understand care , feeding of channels , goroutines, i'm trying build sieve of eratosthenes set of goroutines connected pipeline channels.
here's have far:
// esieve implements sieve of eratosthenes // series of channels connected // goroutines package main import "fmt" func sieve(mine int, inch chan int) { start := true // first-number switch ouch := make(chan int) // output channel instance fmt.printf("%v\n", mine) // print instance's prime next := <-inch; next > 0; next = <-inch { // read input channel fmt.printf("%v <- %v\n",mine,next) // (trace) if (next % mine) > 0 { // divisible prime? if start { // no; first number through? go sieve(next, ouch) // first number - create instance start = false // first time done } else { // not first time ouch <- next // pass next instance } } } } func main() { lim := 30 // let's 30 fmt.printf("%v\n", 2) // treat 2 special case ouch := make(chan int) // create first segment of pipe go sieve(3, ouch) // create instance '3' prime := 3; prime < lim; prime += 2 { // generate 3, 5, ... fmt.printf("send %v\n", prime) // trace ouch <- prime // send down pipe } }
and far goes, works nicely.
however, when finish main loop, main
exits before numbers still in pipeline of sieve
instances have propagated down end.
what simplest, elegant, or accepted way make main routine wait set of goroutines (about 'knows' of first one) complete?
as title question, killing worker goroutines when don't need them anymore: use done idiom. reads closed channel yield 0 value.
make new channel done
. when reads channel succeed, goroutines know should quit. close channel in main when have values need.
check if can read channel done
, , exit returning, or read next when that's available. partially replaces assignment next
in loop:
select { case <-done: return case next = <- inch: }
ranging on channel works, since closing channel exits loop.
as reverse, body question, waiting set of goroutines finish:
use sync.waitgroup
.
var wg sync.waitgroup wg.add(goroutinecount)
and when each goroutine finishes:
wg.done()
or use defer:
defer wg.done()
to wait of them report done:
wg.wait()
in example, call wg.add(1)
when start new goroutine, before call wg.done()
, return. long reach 0 once, wg.wait()
works expected, wg.add(1)
before wg.done
.
Comments
Post a Comment