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