Created
July 1, 2013 07:17
-
-
Save cassava/5898929 to your computer and use it in GitHub Desktop.
An idiom in Go for managing up to a fixed number of workers and separately post-processing the results.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"math/rand" | |
"strings" | |
"time" | |
) | |
// worker does work which takes a (variable) amount of time. | |
// Here it is simulated by waiting a random amount of time. | |
func worker(s string, ch chan<- string) { | |
time.Sleep(time.Duration(rand.Intn(3000)) * time.Millisecond) | |
ch <- s | |
} | |
// manager spawns at most routines amount of workers and connects all the | |
// different entities and functions together. | |
// | |
// manager panics if routines <= 0. | |
func manager(texts []string, routines int) { | |
var ( | |
ch = make(chan string) // for communication between worker and receiver | |
active = make(chan bool, routines-1) // for coordination of multiple workers | |
alive = make(chan struct{}) // blocking as long as receiver is alive | |
) | |
// Start the receiver and start creating workers as quickly as possible. | |
go receiver(ch, active, alive) | |
for _, s := range texts { | |
active <- true | |
go worker(s, ch) | |
} | |
// Signal that we have finished creating workers, then wait for receiver to finish. | |
active <- false | |
<-alive | |
} | |
// receiver evaluates the worker's results one after another. | |
// | |
// For each worker sent into existence, a true value must be queued onto active. | |
// When the last worker has embarked, false should be queued, which causes | |
// receiver to finalize and finish. | |
func receiver(ch <-chan string, active <-chan bool, alive chan<- struct{}) { | |
for <-active { | |
fmt.Print(<-ch, " ") | |
} | |
fmt.Print("\n") | |
close(alive) | |
} | |
func main() { | |
text := "Hello my name is cassava. What is your name? It was nice to meet you!" | |
manager(strings.Split(text, " "), 3) | |
} |
The imports in this gist are only needed for worker
, receiver
, and main
. The pattern itself doesn't require any special imports.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
http://play.golang.org/p/Q46f4Q-B6l