Go语言学习路

Go并发编程Channel

2021-08-06  本文已影响0人  TZX_0710

Channel

单纯地将函数并发执行是没有意义地,函数与函数需要交换数据才能体现并发执行函数地意义。

Go语言的并发模型是CSP,提倡通过通信共享内存而不是通过共享内存实现通信。如果goroutine是并发地执行体,channle就是它们之间的连接。channel是可以让一个goroutine发送特定值到另一个goroutine的通信机制。

Go语言中的通道是一种特殊的类型。通道像一个传送带或者队列,总是遵循先入先出的规则,保证收发顺序。每一个通道都是一个具体类型的导管,也就是声明channel的时候需要为其指定元素类型。

channel类型

channel是一种类型一种引用类型。

var 变量名 chan 元素类型
var ch1 chan bool //声明一个传递布尔类型的通道
var ch2 chan int //声明一个传递整形的通道
var ch3 chan string //声明一个传递字符串的通道

创建channel

通道是引用类型,通道类型的空值是nill

var ch chan int 
//声明后的通道需要使用make进行初始化才能使用
package main

import (
  "fmt"
  "time"
)

func sendMsg(ch chan bool) {
  //写入true到ch通道
  ch <- true
}
func main() {
  //fatal error: all goroutines are asleep - deadlock!
  var ch1 chan bool
  //无缓存通道
  //fatal error: all goroutines are asleep - deadlock!
  //使用如下方式创建通道发送数据会发生的错误
    //原因是无缓冲通道必须要有人接受值得时候才能发送值。
  //第一种方法是采用make(chan bool,1) 创建带缓冲的通道
  //第二种方法就是采用另一个goroutine对该通道进行操作
  //创建的是无缓存通道,无缓冲通道的只要有人接受值的时候才能发送值。
  ch1 = make(chan bool)
  //ch1 <- true
  go sendMsg(ch1)
  //从ch1通道读取参数
  fmt.Println(<-ch1)
  time.Sleep(time.Second * 3)

}
fmt.Println(ch)//nil

从通道循环取值

package main

import "fmt"

func main() {
  //创建无缓冲通道
  ch1 := make(chan int)
  ch2 := make(chan int)
  go func() {
      for i := 0; i < 10; i++ {
          //向ch1写入数据
          ch1 <- i
      }
      //当通道不再需要写入一定要close() 关闭通道!
      close(ch1)
  }()
  go func() {
      for true {
          i, ok := <-ch1 //chan在ch1通道关闭之后 ok的值就变成了false  i就变成了0值当channel关闭且数据都读完了,再读数据会读到该数据类型的零值,且第二个返回值为false
          if !ok {
              break
          }
          ch2 <- i * i //向ch2写入数据
      }
      close(ch2) //关闭ch2通道
  }()
  for i := range ch2 {
      fmt.Println(i)
  }
}

单向通道

有时候在将通道作为参数在多个任务函数间传递,很多时候我们在不同的任务函数中使用通道都会对其进行限制比如限制通道在函数中只能发送或者接受。

//语法 
chan <-int  可以写入的通道
<-chan int 只可以读取的通道
package main

import "fmt"

func write(out chan<- int) {
  //写入该通道
  for i := 0; i < 10; i++ {
      out <- i
  }
  close(out)
}

//交换通道数据
//out 是可以写入的数据 in是只能读取的通道
func square(out chan<- int, in <-chan int) {
  for i := range in {
      out <- i
  }
  close(out)
}
func main() {
  //在函数传参及任何赋值操作中将双向通道转换为单向通道是可以的,但反过来是不可以的。
  //创建2个通道
  ch1 := make(chan int)
  ch2 := make(chan int)
  //ch1被转换成了只可写入的通道
  go write(ch1)
  //ch2变成了可写入 ch1变成了只可读取
  go square(ch2, ch1)
  for i := range ch2 {
      fmt.Println(i)
  }
}

上一篇下一篇

猜你喜欢

热点阅读