[Golang] Magical Channel

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

The channel is a very interesting feature in Golang, and in my experience of using Golang coding, most events will enjoy the pleasure of channel and goroutine coordination. So this article mainly introduces some interesting usages of channel.

Here is a description of the channel in the Go programming language specification of the oling Cat translator:

A channel provides a mechanism for synchronizing between two concurrently executed functions and communicating by passing values that correspond to the type of the channel element.

This description is tedious and boring. When I first read it, I couldn't understand exactly what it was. In fact, the channel can be thought of as a pipe or FIFO queue, very simple and lightweight. The channel is not the Golang initiative. It also appears as a built-in feature in other languages. In most cases, it is a feature of a large, clumsy, and complex Message Queuing system.

Let's get some fun together!

The most common way: producer/Consumer

The producer generates some data to put it into the channel, and then the consumer takes the data out of the channel in order, one by one, for processing. This is the most common way of using channel. When the buffer of the channel is exhausted, the producer must Wait (block). In other words, if there is no data in the channel, consumers will have to wait.

The source code for this example is here. It is best to download to run locally.

Producers

func producer(c chan int64, max int) {    defer    close(c)    for i:= 0; i < max; i ++ {        c <- time.Now().Unix()    }}

The producer generates a number of "Max" Int64, and puts it in channel "C". It is important to note that the channel is closed with defer when the function is launched.

Consumers

func consumer(c chan int64) {    var v int64    ok := true    for ok {        if v, ok = <-c; ok {            fmt.Println(v)        }    }}

Read a int64 number from one of the channel, and then print it on the screen. When the channel is closed, the variable "OK" is set to "false".

Self-growing ID generator

When the birth lets the production person can produce the integer sequentially. It is a self-growing ID generator. I have encapsulated this function as a package. and host its code here. Use the example to refer to the code here.

type AutoInc struct {    start, step int    queue       chan int    running     bool}func New(start, step int) (ai *AutoInc) {    ai = &AutoInc{        start:   start,        step:    step,        running: true,        queue:   make(chan int, 4),    }    go ai.process()    return}func (ai *AutoInc) process() {    defer func() { recover() }()    for i := ai.start; ai.running; i = i + ai.step {        ai.queue <- i    }}func (ai *AutoInc) Id() int {    return <-ai.queue}func (ai *AutoInc) Close() {    ai.running = false    close(ai.queue)}

Signal Volume

Semaphores are also an interesting application of channel. Here's an example from "Effective go". You should have read it, haven't you? If not, start reading now ...

I used the semaphore in the API package gearman-go for the Gearman service. In Worker/worker.go 232 rows, the number of parallel worker.exec is reached Worker.limit, it will be blocked.

var sem = make(chan int, MaxOutstanding)func handle(r *Request) {    sem <- 1 // 等待放行;    process(r)    // 可能需要一个很长的处理过程;    <-sem // 完成,放行另一个过程。}func Serve(queue chan *Request) {    for {        req := <-queue        go handle(req) // 无需等待 handle 完成。    }}

Random sequence Generator

Of course, you can modify the self-growth ID generator. Let the producer generate random numbers into the channel. But it's kind of boring, isn't it?

Here is another implementation of the random sequence generator. Inspiration comes from the language specification. It randomly generates a sequence of 0/1:

func producer(c chan int64, max int) {    defer close(c)    for i := 0; i < max; i++ {        select { // randomized select        case c <- 0:        case c <- 1:        }    }}

Timeout timer

When a channel is Read/write blocked, it will be blocked forever until the channel is closed and a panic is generated. The channel has no built-in timer for timeouts. And there seems to be no plan to add such a feature to the channel. But in most cases, we need a timeout mechanism. For example, there was an error in the execution of the producer, so no data was placed into the channel. Consumers will be blocked until the channel is closed. Turn off the channel every time it goes wrong? This is definitely not a good idea.

Here's a solution:

c := make(chan int64, 5)defer close(c)timeout := make(chan bool)defer close(timeout)go func() {    time.Sleep(time.Second) // 等一秒    timeout <- true // 向超时队列中放入标志}()select {case <-timeout: // 超时    fmt.Println("timeout...")case <-c: // 收到数据    fmt.Println("Read a date.")}

Did you notice the SELECT statement? Which channel has data first, which branch executes first. So...... Do you need more explanations?

This is also used in the client API implementation of Gearman-go, line No. 238.

After the English version of this article was released, @mjq reminded me that I could use time. After. In the project, this is really a better notation. I have to thank him! I also read the 74th line of Src/time/sleep.go, time. The implementation of After. Its internal implementation is exactly the same as the code above.

And more ...

The various interesting applications mentioned above can of course be implemented in other message queues, but because of the simplicity and lightness of the channel, it makes sense for the Golang channel to realize these interesting features and has real-world applications. In fact, I think the interesting channel usage is much more than that. If you find other interesting gameplay, be sure to let me know. Thank you!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.