- This article mainly talk about practice, the principle part will be a stroke, about the go language concurrency implementation and memory model follow-up will have articles.
- Channel realization of the source code is not complex, recommended reading,
https://github.com/golang/go/blob/master/src/runtime/chan.go
What does the channel do?
Significance:channel 是用来通信的
In fact: (The data is copied and passed through the channel, essentially a queue)
Where should the channel be used?
Core:需要通信的地方
For example, the following scenario:
- Notification broadcast
- Exchanging data
- Explicit synchronization
- concurrency control
- ...
Remember! Channel is not used to implement the lock mechanism, although some places can be used to achieve similar read and write locks, protect the function of critical areas, but do not use it!
Channel use case implementation
Timeout control
// 利用 time.After 实现func main() { done := do() select { case <-done: // logic case <-time.After(3 * time.Second): // timeout }}func do() <-chan struct{} { done := make(chan struct{}) go func() { // do something // ... done <- struct{}{} }() return done}
Take the fastest results
A more common scenario is retry, the first request does not return a result within a specified timeout, and retries the second time, taking two times the fastest returned result.
The time-out control is above, and the code section below is a simple implementation called multiple times.
func main() { ret := make(chan string, 3) for i := 0; i < cap(ret); i++ { go call(ret) } fmt.Println(<-ret)}func call(ret chan<- string) { // do something // ... ret <- "result"}
Limit the maximum number of concurrent
// 最大并发数为 2limits := make(chan struct{}, 2)for i := 0; i < 10; i++ { go func() { // 缓冲区满了就会阻塞在这 limits <- struct{}{} do() <-limits }()}
For...range Priority
for ... range c { do }This is equivalent toif _, ok := <-c; ok { do }
func main() { c := make(chan int, 20) go func() { for i := 0; i < 10; i++ { c <- i } close(c) }() // 当 c 被关闭后,取完里面的元素就会跳出循环 for x := range c { fmt.Println(x) }}
Multiple Goroutine Synchronous responses
Using the Close broadcast
func main() { c := make(chan struct{}) for i := 0; i < 5; i++ { go do(c) } close(c)}func do(c <-chan struct{}) { // 会阻塞直到收到 close <-c fmt.Println("hello")}
Non-blocking Select
Select itself is blocked, when all branches are not satisfied will always block, if you want to not block, then a nothing to do the default branch is the best choice
select {case <-done: returndefault: }
for{select{}} terminated
Try not to use the break label form, but to put the condition of the terminating loop in the for condition.
for ok { select { case ch <- 0: case <-done: ok = false }}
Not to be continued
...
Channel characteristics
Basic Features
| Operation |
channel with nil value |
the channel that was closed |
Normal channel. |
| Close |
Panic |
Panic |
Successfully closed |
| c<- |
Block Forever |
Panic |
Blocked or successfully sent |
| <-c |
Block Forever |
Never block |
Blocked or successfully received |
Happens-before characteristics
- No buffering, receive Happens-before send
- In any case, send Happens-before receive
- Close Happens-before Receive
Reference
- Https://go101.org/article/channel.html
- Https://golang.org/doc/effective_go.html#channels