Golang Channel 高并发的初始

2,488 阅读2分钟

go中channel是一种重要的引用数据类型,可以看作是管道,可以通过并发的核心单元发送或者接收数据进行通讯。

操作符 <-,箭头指向,即数据的流向,没有指明方向,那么Channel就是双向的,既可以接收数据,也可以发送数据

ch <- v         // 发送值到Channel ch中
v := <-ch       // 从Channel ch中接收数据,并赋值给v

// 初始化 Channel ch, 类似于Slice,map的数据类型一样,channel必须先创建,然后再使用

ch := make(chan  int)

Channel的方向

  • 不确定双向性、指定唯一单向
chan T          // 既可以接收数据,也可以发送数据
chan<- float64  // 只可以用来发送 float64 类型的数据
<-chan int      // 只可以接收 float64 数据类型的数据
  • <-总是优先和最左边的类型结合
chan<- chan int    // 等价 chan<- (chan int)
chan<- <-chan int  // 等价 chan<- (<-chan int)
<-chan <-chan int  // 等价 <-chan (<-chan int)
chan (<-chan int)

设置Channel的容量,代表Channel缓存的大小

make初始化的时候可以设置 如果没有设置Channel的大小,或者设置为0,那么默认Channel的没有缓存的,当接收者和发送者都准备好了后,他们通讯才会发生阻塞(blocking) 如果我们设置了缓存的大小,那么就有可能不会发送阻塞了,只有buffer满了后,发送者才会阻塞,只有清空了缓存,接收者才会阻塞。 一个nil的Channel不会通讯。

make(chan int, 100)

关闭Channel

内置的方法close()可以关闭Channel,如何检测Channel是否被关闭

defer close(c)          // 关闭 channel

v, ok := <-ch           // 检测 channel是否被关闭

select的使用,类似于switch

case用可能处理的接收语句,有可能是发送语句,还有可能是默认 default

timeout 超时处理

如果没有case需要处理,select语句就会一直阻塞着

import "time"
import "fmt"
func main() {
    c1 := make(chan string, 1)
    go func() {
        time.Sleep(time.Second * 2)
        c1 <- "result 1"
    }()
    
    select {
        case res := <-c1:
            fmt.Println(res)
        case <-time.After(time.Second * 1):
            fmt.Println("timeout 1")
    }
}

其实使用time.After函数,它是返回一个<-chan Time的单向channel,在指定时间发送一个当前时间给返回的channel中

同步

channel可以用在goroutine之间的同步

import (
	"fmt"
	"time"
)
func worker(done chan bool) {
	time.Sleep(time.Second)
	// 通知任务已完成
	done <- true
}
func main() {
	done := make(chan bool, 1)
	go worker(done)
	// 等待任务完成
	<-done
}

生产者和消费者


package main

import (
	"fmt"
	"time"
)

func main() {

	fmt.Println("show channel")
	queue := make(chan int, 1)
	go test.Producer(queue)
	go test.Consumer(queue)
	time.Sleep(1e9)
}

func Producer(queue chan<- int)  {
	for i := 0; i < 10; i++ {
		fmt.Println("send:", i)
		queue<- i+10000
	}
}

func Consumer(queue <-chan int) {
	for i := 0; i < 10; i++ {
		v := <-queue
		fmt.Println("receive:", v)
	}
}