This is a creation in Article, where the information may have evolved or changed.
The following design patterns and scenarios come from the ppt:https://talks.golang.org/2012/concurrency.slide on Goroutine on Google io
The sample code for this article is in: Https://github.com/hit9/Go-patterns-with-channel
Generator
In Python we can use yield keywords to make a function a generator, and in go we can use the channel to make generators (something like lazy load).
Of course, our channel is not simply to do the function of blocking the main line to use OH.
Here is an example of making an auto-increment integer generator, until the main line asks for data from the channel, we add the data to the channel
Func xrange () Chan int{//Xrange used to generate the self-increment of the integer var ch chan int = make (chan int) go func () {//out a goroutine for I : = 0;; i++ { ch <-i //until channel request data, only add I to channel } } () return Ch}func main () { Generator: = Xrange () for i:=0; i <; i++ { //We generate 1000 self-increment integers! FMT. Println (<-generator) }}
It reminds me of the cute Python xrange , so I gave the generator the name!
Service of
For example, when we load a Web site, such as when we log on to Sina Weibo, our message data should come from a separate service, which is only responsible for returning a user's new message reminder.
Here is an example of use:
Func get_notification (User string) Chan string{ / * * Here you can query the database for new messages, etc... * /notifications: = Make (chan string) go func () {//Hang a channel out notifications <-FMT. Sprintf ("Hi%s, Welcome to weibo.com!", user) } () return Notifications}func main () { Jack: = get_ Notification ("Jack")// get Jack's message Joe: = Get_notification ("Joe")//Get Joe's message //Get the message back to FMT. Println (<-jack) FMT. Println (<-joe)}
Multi-channel composite
The above example uses a channel as the return value, which merges the channel data into a single channel. In this case, however, we need to output our return value sequentially (FIFO).
As below, we assume that we want to calculate a very complex operation 100-x , divided into three-way calculation, and finally unified in a channel to take out the results:
Func do_stuff (x int) int {//a relatively time-consuming thing, such as calculation of timing . Sleep (time. Duration (Rand. INTN (Ten)) * time. MILLISECOND)//Analog calculation return 100-x//If 100-x is a time-consuming calculation}func branch (x int) Chan int{//Each branch leaves a goroutine to do the calculation and flows the results into confidence DAO ch: = make (chan int) go func () { ch <-do_stuff (x) } () return ch}func fanin (CHS ... chan int) chan int { ch: = make (chan int) for _, c: = Range CHS { //note here explicitly value go func (c chan int) {ch <-<-C} (c) Compound } return Ch}func main () { Result: = Fanin (Branch (1), Branch (2), Branch (3)) for I: = 0; i < 3 ; i++ { FMT. Println (<-result) }}
Select Monitoring Channel
Go has a statement called select , which monitors the flow of data across channels.
The following program is a use example of SELECT, we monitor three channels of data outflow and collect data into one channel.
func foo (i int) Chan int { c: = make (chan int) go func () {C <-i} () return C}func main () { C1, c2, C 3: = foo (1), Foo (2), Foo (3) c: = make (chan int) go func () {//Open a goroutine monitor each channel data output and collect data to channel C for { Selec t {//monitor C1, C2, C3 outflow, and all incoming channels C case v1: = <-c1:c <-v1 Case v2: = <-c2:c <-v2 case v3: = &L t;-c3:c <-v3 }}} () //block mainline, remove the data for Channel C for I: = 0; i < 3; i++ { fmt. PRINTLN (<-C)//from print to see our data output is not strictly in the order of the} }
With SELECT, our functions in the example code in the multiplexing fanIn can be written in this way (so that you don't have to open a few goroutine to fetch the data):
Func fanin (Branches ... chan int) chan int { c: = make (chan int) go func () {for I: = 0; i < len (branch ES); i++ {//select will attempt to fetch data from each channel in turn select {Case v1: = <-branches[i]: C <-v1 }} () Return C}
When using SELECT, sometimes time-outs are required, where the timeout channel is quite interesting:
Timeout: = time. After (1 * time. Second)//timeout is a timing channel, if time is reached, a signal will be sent out for is_timeout: = false;!is_timeout; { Select {///monitor channel C1, C2, C3, timeout channel data outflow case v1: = <-c1:fmt. Printf ("received%d from C1", v1) Case v2: = <-c2:fmt. Printf ("received%d from C2", v2) case v3: = <-c3:fmt. Printf ("Received%d from C3", V3) case <-timeout:is_timeout = TRUE//timeout }}
End Flag
In go concurrency with parallel notes one of the most important and common applications we've talked about is the use of unbuffered channels to block the main line and wait for the goroutine to end.
So we don't have to use timeout again.
Then update the scheme for the above timeout to end the main line:
Func Main () { c, quit: = make (chan int), make (chan int) go func () { C <-2 //Add Data quit <-1// Send Complete Signal } () for is_quit: = false;!is_quit; { Select {///monitor channel C data outflow case V: = <-c:fmt. Printf ("received%d from C", v) case <-quit:is_quit = TRUE//Quit channel has output, Close for Loop }} }
Daisy Chain
Simply put, the data flows from one end to the other, looking like a linked list, and wondering why you should take such an awkward name.
The English name of the daisy chain is called: Daisy-chain, one of its applications is to make filters, for example, we can sift under 100 prime number (you need to know what is the Sieve method first)
The program has a detailed comment, no longer explained.
/* * Using Channel daisy-chain sieve method to find the prime number of an integer range * Sieve method to find the prime number of the basic idea is: to start from 1, a range of positive integers from small to large order, * 1 is not a prime, first sieve it off. The remainder of the number selected is the prime number, and then the multiplier is removed. * And so on, until the sieve is empty when the end */package Mainimport "FMT" func xrange () Chan int{//starting from 2 the integer generator var ch chan int = make (chan int) Go func () {//Open a goroutine for i: = 2;; i++ {ch <-I//until channel request data, only add I into Channel}} () re Turn Ch}func filter (in Chan int, number int) Chan int {///Enter an integer queue, sift out a multiple of number, not a multiple of number into the output queue//in: Input queue Out: = Make (chan int) go func () {for {i: = <-in//from input take an if I% number! = 0 { Out <-I//Put output Channel}}} () return Out}func main () {const MAX = 100//Find out within 100 There are primes nums: = xrange ()//Initialize an integer generator number: = <-nums//Catch an integer from the generator (2) as the initialization integer for number <= max {//Numbe R as a sieve, when the sieve exceeds Max, the filter fmt ends. PRINTLN (number)//print prime, sieve is a prime number nums = Filter (nums, number)//sieve out number multiples of number = <-nums//Update Sieve} }
Random number generator
The channel can be used as a generator, and as a special example, it can also be used as a random number generator. Here is a random 01 generator:
Func rand01 () chan int { ch: = make (chan int) go func () { for { Select {//select will attempt to execute each case, if all can be executed, then with Machine Select an execution case CH <-0: Case ch <-1: } } } () return Ch}func main () { Generator: = Rand0 1 ()//Initialize a 01 random generator //test, Print 10 random for I: = 0; i < i++ { FMT. Println (<-generator) }}
Timer
We have just actually contacted the channel as a timer, time in the bag After will make a timer.
Take a look at our timers!
/* * Use Channel to do timer */package Mainimport ( "FMT" "Time") Func Timer (duration time. Duration) chan bool { ch: = Make (chan bool) go func () {Time . Sleep (duration) ch <-true//to TIME! } () return Ch}func main () { timeout: = Timer (time. Second)//timer 1s for { Select {case <-timeout: fmt. Println ("Already 1s!")//To TIME return //End Program}} }
Todo
Examples of Google's application scenarios.
This article mainly summarizes the use of channel, goroutine some design patterns.