design patterns - Go - why do scheduling goroutine background workers also requires its own goroutine? -
i'm working on picking few of concurrency patterns of go. looked @ implementing background workers using goroutines , input/output channels, , noticed when sending new jobs receiving channel (essentially enqueuing new jobs) have in goroutine or scheduling gets messed up. meaning:
this crashes:
for _, jobdata := range(dataset) { input <- jobdata }
this works:
go func() { _, jobdata := range(dataset) { input <- jobdata } }()
for more concrete, played nonsense code (here in go playground):
package main import ( "log" "runtime" ) func dowork(data int) (result int) { // ... 'heavy' computation result = data * data return } // processing of input , return // results on output channel func worker(input, output chan int) { data := range input { output <- dowork(data) } } func scheduleworkers() { input, output := make(chan int), make(chan int) := 0 ; < runtime.numcpu() ; i++ { go worker(input, output) } numjobs := 20 // doesn't work // , crashes program /* := 0 ; < numjobs ; i++ { input <- } */ // go func() { := 0 ; < numjobs ; i++ { input <- } }() results := []int{} := 0 ; < numjobs ; i++ { // read off results result := <-output results = append(results, result) // stuff... } log.printf("result: %#v\n", results) } func main() { scheduleworkers() }
i'm trying wrap head around subtle difference - appreciated. thanks.
your scheduleworks
function sends, in main goroutine (ie. 1 runs main()
function, in program starts), value via input
. worker
receives it, , sends value via output
. there nobody receiving output
@ point, program can't go on, , main goroutine sends next value worker
.
repeat reasoning each worker. have runtime.numcpu()
workers, less numjobs
. let's runtime.numcpu() == 4
, have 4 workers. @ end, have sent 4 values, each 1 one worker
. since nobody reading output
, workers busy trying send, can't accept more data via input
, fifth input <- i
hang. @ point every goroutine waiting; that's deadlock.
you notice that, if launch 20 or more workers instead of runtime.numcpu()
, program works. that's because main goroutine can send wants via input
, since there enough workers receive them.
if, instead of of this, put input <- i
loop in goroutine, in successful example, main
goroutine (in scheduleworks
runs) can go on , start reading output
. so, each time new goroutine sends value, worker sends via output
, main goroutine gets output, , worker can receive value. nobody waits, , program succeeds.
Comments
Post a Comment