github.com/robert-zaremba/parexec@v0.0.0-20150611124707-8929690d3378/worker_test.go (about) 1 package parexec 2 3 import ( 4 "fmt" 5 "sync" 6 "testing" 7 "time" 8 ) 9 10 func ExampleSimpleRun() { 11 total := 4 12 type Job struct { 13 Name string 14 Duration int 15 } 16 jobs := make(chan *Job) 17 // use buffered channel to be able to fill all jobs and start getting results without blocking workers 18 results := make(chan string, total) 19 work := func(stop <-chan bool) { 20 for { 21 select { 22 case j := <-jobs: 23 time.Sleep(time.Duration(j.Duration)) 24 results <- j.Name 25 case <-stop: 26 fmt.Println("closing") 27 return 28 } 29 } 30 } 31 done := func() { 32 close(jobs) 33 } 34 stop := SimpleRun(2, work, done) 35 // fill jobs 36 for i := 0; i < total; i++ { 37 jobs <- &Job{Name: fmt.Sprint(i), Duration: i * 1000} 38 } 39 // you can't use this: close(results); for r := range results 40 // because close(results) is not safe - there might be active goroutine 41 // which didn't get stop signal and tries to write to results 42 for i := 0; i < total; i++ { 43 r := <-results 44 fmt.Println(r) 45 } 46 close(stop) 47 // Wait for closing workers. 48 // Normally you should do it with separate channel (in a clojure, handled in `case <-stop:`) to get acknowledges 49 time.Sleep(200000) 50 // Output: 51 // 0 52 // 1 53 // 2 54 // 3 55 // closing 56 // closing 57 } 58 59 func ExampleSimpleRun_singleloop() { 60 var jobs = make(chan int) 61 var results = make(chan int) 62 work := func(stop <-chan bool) { 63 for { 64 select { 65 case j := <-jobs: 66 results <- j 67 case <-stop: 68 return 69 } 70 } 71 } 72 done := func() { 73 close(results) 74 } 75 stop := SimpleRun(2, work, done) 76 sum, r := 0, 0 77 for i := 0; i < TOTALBENCH; { 78 select { 79 case jobs <- i: 80 i++ 81 case r = <-results: 82 sum += r 83 } 84 } 85 close(stop) // we need to manually stop to automatically stop results when all workers will finish 86 for r = range results { 87 sum += r 88 } 89 } 90 91 // ExampleSimpleRun_raw present the same computation as ExampleSimpleRun_singleloop 92 // without using SimpleRun function and stop channel. 93 func ExampleSimpleRun_raw() { 94 var jobs = make(chan int) 95 var results = make(chan int) 96 var wg sync.WaitGroup 97 for i := 0; i < 2; i++ { 98 wg.Add(1) 99 go func() { 100 for j := range jobs { 101 results <- j 102 } 103 wg.Done() 104 }() 105 } 106 go func() { 107 wg.Wait() 108 close(results) 109 }() 110 sum, r := 0, 0 111 for i := 0; i < TOTALBENCH; { 112 select { 113 case jobs <- i: 114 i++ 115 case r = <-results: 116 sum += r 117 } 118 } 119 close(jobs) // we need to close jobs to stop workers and close results 120 for r = range results { 121 sum += r 122 } 123 } 124 125 func BenchmarkSimpleRun(*testing.B) { 126 ExampleSimpleRun_singleloop() 127 } 128 129 func BenchmarkSimpleRun_raw(*testing.B) { 130 ExampleSimpleRun_raw() 131 }