[Golang] channel passage

Explanation

channel is among a core types go, can be seen as a pipe. The core unit may concurrently transmit and receive data through the channel, thereby realizing communication.

In go, Channel is a data type, mainly to solve the problem of data between the synchronization and coroutine coroutine shared (data transfer) is.

go among goroutine run in the same address space, access to shared memory address must be prepared to synchronize, goroutine pursue shared memory through communication, rather than shared memory for communication.

Reference types can be used for multiple goroutine communication channel, in its internal implementation synchronization, to ensure concurrency safety.

Variables defined channel

In go, channel also corresponds to a structure of the underlying data created make a reference .

When we copy a channel or a function parameter passing, we just copy a reference channel, so the caller and the callee will reference the same channel objects, and other reference types, a value of zero channel is also nil.

Define a channel when transmitting to the need to define the type of channel values, the channel can make use of the built-in function to create.

chan is used to create a keyword channel, Type represents the type of channel data transceiver.

make(chan Type) // 等价于make(chan Type,0)
make(chan Type,capacity)

When the parameter when capacity = 0, Channel unbuffered blocking read and write; when capacity> 0 when, Channel buffer, is non-blocking, until it fills capacity element does not block write.

channel much like the life of the pipeline, while you can store things on the other side of things can be removed. channel by operator <- to receive and transmit data, transmission and reception of data syntax:

package main

import "fmt"

func main() {
    // 创建一个channel
    ch := make(chan int)
    // 创建一个子goroutine,在这个goroutine中进行数据的写入
    go worker(ch)
    // 读取channel通道中的数据
    num := <- ch
    fmt.Println("channel通道中读到的数据为:",num)
}

func worker(ch chan int) {
    // 向channel通道中写入数据
    ch <- 10
}

In the above code, we adopted chan <- to write channel values ​​val, by val: = <- chan for reading values ​​channel.

We first created a goroutine write data to the channel used for the pipeline, and then simultaneously reading data in the main goroutine in.

The resulting output is:

channel通道中读到的数据为: 10

Process finished with exit code 0

If channel (unbuffered) occurs in a read or write operation, and in an additional operation corresponding to no, then blocking occurs, until the other end of the respective channel operation occurs.

By default, all receive and transmit data Channel blocked, unless the other end is ready, so that the synchronization goroutine become more simple, and no explicit lock.

package main

import (
    "fmt"
)

func main() {
    c := make(chan int)

    go func() {
        defer fmt.Println("子协程结束")

        fmt.Println("子协程正在运行……")

        c <- 666 //666发送到c
    }()

    num := <-c //从c中接收数据,并赋值给num

    fmt.Println("num = ", num)
    fmt.Println("main协程结束")
}

Result of the program:

When reading data, the following form may be used to determine whether the transmission data is completed:

 x, ok := <-channel 

If the data transfer is complete, ok is false, otherwise true.

package main

import "fmt"

func main() {
    // 创建一个channel
    ch := make(chan int)

    // 创建一个goroutine用来向channel中写入数据
    go func() {
        defer close(ch) // 通过close函数可以关闭channel通道
        for i:=0;i<5;i++ {
            ch <- i // 将i值写入channel
        }
    }()

    // 在主goroutine中读取channel通道传递的值
    for {
        val,ok := <-ch
        if !ok { // ok 为false时表示读取结束
            fmt.Println("读取结束,over")
            break
        }
        fmt.Println("读取到的数据为:",val)
    }
}

The resulting output is:

读取到的数据为: 0
读取到的数据为: 1
读取到的数据为: 2
读取到的数据为: 3
读取到的数据为: 4
读取结束,over

Debugger finished with exit code 0

Unbuffered defined channel

Unbuffered channel (unbuffered channel) that are not the ability to save the value of the channel before receiving any.

This type of transmission channel requirements goroutine goroutine simultaneously receiving and ready to complete the transmit and receive operations. Otherwise, the path will lead to the implementation of goroutine send or receive operation of the first block waiting.

This interactive behavior of the transmit and receive channels is itself synchronized. Wherein any one of the operations can not operate alone away from the other.

For example we write the above procedure are in fact unbuffered channel.

Obstruction: for some reason the data does not arrive, the current coroutine (threads) continue to be in a waiting state until conditions are met, only the contact obstruction.

Synchronization: between two or more coroutine (threads), the contents of the data consistency holding mechanism.

The following figure shows how to use two unbuffered goroutine to share a channel value:

Defined buffer of channel

Channel buffer (buffered channel) is a channel capable of storing one or more data values ​​before being received.

This type of passage is not mandatory to be completed between the sending and receiving simultaneously goroutine. Channel conditions will block operation of transmitting and receiving are different.

Not only the value of the channel to be received, the reception operation will be blocked.

Value only when the channel is not receiving buffer is available to be transmitted, the transmission operation will be blocked.

This results in a buffer between the channel and the channel unbuffered very different: unbuffered channels ensure transmission and reception of data exchange goroutine will at the same time; there is no such guarantee buffered channel.

Example is as follows:

Create a buffer of channel format:

make(chan Type, capacity)

If the buffer capacity of a given channel is asynchronous. As long as there is unused space in the buffer used to send data, or further comprising data may be received, then the communication will be performed without blocking.

package main

import "fmt"

func main() {
    // 定义一个有缓冲的channel
    ch := make(chan int,2)

    // 创建一个goroutine,用来写入数据
    go func() {
        defer close(ch)
        for i:=0;i<5;i++ {
            ch <- i
            fmt.Println("写入的数据为:",i) // print操作属于io操作,可能导致cpu时间片切换
        }
    }()

    for {
        num,ok := <- ch
        if !ok {
            fmt.Println("读取结束,over")
            break
        }
        fmt.Println("读取到的数据为:",num)
    }
}

Operating results as follows:

写入的数据为: 0
读取到的数据为: 0
读取到的数据为: 1
写入的数据为: 1
写入的数据为: 2
写入的数据为: 3
写入的数据为: 4
读取到的数据为: 2
读取到的数据为: 3
读取到的数据为: 4
读取结束,over

Process finished with exit code 0

Close channel

If the sender know that there is no need to send more value to the channel, then let the recipient can know in time can receive no extra value would be useful, because the receiver can stop receiving the unnecessary wait. This can be achieved through close channel built-close function.

package main

import (
    "fmt"
)

func main() {
    c := make(chan int)

    go func() {
        for i := 0; i < 5; i++ {
            c <- i
        }
        //把 close(c) 注释掉,程序会一直阻塞在 if data, ok := <-c; ok 那一行
        close(c)
    }()

    for {
        //ok为true说明channel没有关闭,为false说明管道已经关闭
        if data, ok := <-c; ok {
            fmt.Println(data)
        } else {
            break
        }
    }

    fmt.Println("Finished")
}

Result of the program:

note:

  • channel need not often go to the same file is closed only when you really do not have any data to send, or you want to explicitly end the cycle range and the like, only to close the channel;

  • After closing the channel, can no longer send data (errors received after initiation panic immediately returns a zero value) to the Channel;
  • After closing the channel, you can continue to receive data from Channel;
  • For nil channel, regardless of the transceiver will be blocked.

You can use range to iterate continue to operate channel:

package main

import (
    "fmt"
)

func main() {
    c := make(chan int)

    go func() {
        for i := 0; i < 5; i++ {
            c <- i
        }
        //把 close(c) 注释掉,程序会一直阻塞在 for data := range c 那一行
        close(c)
    }()

    for data := range c {
        fmt.Println(data)
    }
    fmt.Println("Finished")
}

One-way channel

By default, the channel is a bidirectional channel, i.e., transmit data may be entered with the data to be received inside.

However, we often see a channel passed as a parameter and the value that the other party is using a one-way, or just let it send data, or just let it receives data, we can specify the direction of the channel at this time.

One-way channel variable declaration is very simple, as follows:

var ch1 chan int       // ch1是一个正常的channel,是双向的
var ch2 chan<- float64 // ch2是单向channel,只用于写float64数据
var ch3 <-chan int     // ch3是单向channel,只用于读int数据
//   chan<- //只写
func counter(out chan<- int) {
    defer close(out)
    for i := 0; i < 5; i++ {
        out <- i //如果对方不读 会阻塞
    }
}

//   <-chan //只读
func printer(in <-chan int) {
    for num := range in {
        fmt.Println(num)
    }
}

func main() {
    c := make(chan int) //   chan   //读写

    go counter(c) //生产者
    printer(c)    //消费者

    fmt.Println("done")
}

Guess you like

Origin www.cnblogs.com/liujunhang/p/12536331.html