GO 语言关键字 chan

1,353 阅读3分钟

chan 通道,可以理解成管道.从一端读入,从另一端输出

1、定义通道的方式(主要是定义通道的类型变量,指定该通道内只能存放这一类型的数据): var 变量名 chan 变量类型 例如:var chanweb chan int

2、初始化通道(创建通道)通道的零值是nil demo := make(chan int) 当我们复制一个channel或用于函数参数传递时,我们只是拷贝了一个channel引用。 两个channels的比较可以使用==进行比较。如果两个channel内引用相同的对象,则返回真

3、一个channel有发送和接受两个主要操作,都是通信行为。 一个发送语句将一个值从一个goroutine通过channel发送到另一个执行接收操作的goroutine。发送和接收两个操作都使用<-运算符。在发送语句中,<-运算符分割channel和要发送的值。在接收语句中,<-运算符写在channel对象之前。一个不使用接收结果的接收操作也是合法的。

ch <- x // 一个发送语句 把X发送到ch中
x = <-ch // 赋值语句中的接收表达式 从ch 接收数据 并把值赋给 v
<-ch // 一个接收语句;结果被丢弃一个

Channel还支持close操作,用于关闭channel,随后对基于该channel的任何发送操作都将导致panic异常。 对一个已经被close过的channel进行接收操作依然可以接受到之前已经成功发送的数据; 如果channel中已经没有数据的话将产生一个零值的数据。 使用内置的close函数就可以关闭一个channel:例如:

close(ch)

chan 中的缓存

不带缓冲区的channel

不带缓冲区的chan的缓冲区大小是0。 不带缓冲区的chan线程写入时会立马发生阻塞,直到有其他线程有对该chan执行接收操作且接收成功后,写入的进程才会解除阻塞。 不带缓冲区的chan线程接收时也会立马发生阻塞,直到有其他线程对该chan执行写入操作后,接收的线程才会解除阻塞。 例子:

ch := make(chan int)
go func() {
   time.Sleep(time.Second*3)
   fmt.Println("receive over")
   <- ch
}()

ch<-1
fmt.Println("send over")

带缓存的Channels

带缓存的Channel内部持有一个元素队列。队列的最大容量是在调用make函数创建channel时通过第二个参数指定的。

ch = make(chan string, 3)

向缓存Channel的发送操作就是向内部缓存队列的尾部插入原因,接收操作则是从队列的头部删除元素。 获取channel的有效长度可以使用内置函数len或者cap

管道### 串联的Channels

Channels也可以用于将多个goroutine连接在一起,一个Channel的输出作为下一个Channel的输入。这种串联的Channels就是所谓的管道(pipeline)

单方向的Channel

可以在函数中定义chan,只允许chan单方向的发送和接收。

类型chan<- int表示一个只发送int的channel,只能发送不能接收。相反,类型<-chan int表示一个只接收int的channel,只能接收不能发送。(箭头<-和关键字chan的相对位置表明了channel的方向。)这种限制将在编译期检测。

//单方向的chan
func counter(out chan <-int)  {
   for x:=1;x < 100;x++ {
      out <- x
   }
   close(out)
}

func  squarer(out chan <- int,in <-chan int )  {
   for v:=range in{
      out <- v * v
   }
   close(out)
}

func printer(in <-chan int)  {
   for v:=range in{
      fmt.Println(v)
   
```
```