golang之管道

一、基本介绍

  1. channle本质就是一个数据结构-队列
  2. 数据是先进先出
  3. 线程安全,多个goroutine访问时,不需要加锁,就是说channel本身就是线程安全的
  4. channel是有类型的,一个string的channel只能存放string类型数据

二、定义/声明channel

var 变量名 chan 数据类型

示例:

var intChan chan int                  // (intChan用于存放int数据)
var mapChan chan map[string]string    // (mapChan用于存放map[string]string类型)
var perChan chan Person               // (perChan用于存放Person类型)
var perChan2 chan *Person             // (perChan2用于存放Person的指针类型)

说明:

  1. channel是引用类型
  2. channel必须初始化才能写入数据,即make后才能使用
  3. 管道是有类型的,intChan只能存放整数int

三、channel(管道)-基本使用

  1. channel初始化
package main

import "fmt"

func main() {
	var intChan chan int
	intChan = make(chan int, 3)
	fmt.Printf("intChan的值=%v\n", intChan) // intChan的值=0xc00007a080
}

说明:可以看出管道是引用类型>说明:可以看出管道是引用类型

  1. 向channel中写入数据和读取数据
package main

import "fmt"

func main() {
	var intChan chan int
	intChan = make(chan int, 3)
	// 向管道中写入数据
	intChan <- 100
	num := 200
	intChan <- num
	intChan <- 300
	// intChan <- 10 // 注意点:当我们给管道写入数据时,不能超过其容量.否则会报all goroutines are asleep - deadlock!
	// 看看管道的长度和容量
	fmt.Printf("channel len=%v cap=%v \n", len(intChan), cap(intChan)) // channel len=3 cap=3
	// 从管道中读取数据
	num1 := <-intChan
	num2 := <-intChan
	num3 := <-intChan
	fmt.Printf("num1=%v,num2=%v,num3=%v\n", num1, num2, num3) // num1=100,num2=200,num3=300
	// 在没有使用协程的情况下,如果我们管道的数据已经全部取出,再取就会报错
	// num4 := <-intChan // 报错all goroutines are asleep - deadlock!
}

说明:

  1. 当我们给管道写入数据时,不能超过其容量.否则会报all goroutines are asleep - deadlock!
  2. 在没有使用协程的情况下,如果我们管道的数据已经全部取出,再取就会报错

四、注意事项

  1. channel只能存放指定数据类型
  2. channel的数据类型放满后,就不能放入了
  3. 如果从channel取出数据后,可以继续放入
  4. 在没有使用协程的情况下,如果如果channel数据取完了,再取,就会报dead lock

五、channel的关闭

使用内置函数close可以关闭channel,当channel关闭后,就不能再向channel写数据了,但是任然可以从channel读取数据

package main

import "fmt"

func main() {
	var intChan chan int
	intChan = make(chan int, 3)
	// 向管道中写入数据
	intChan <- 100
	num := 200
	intChan <- num
	// 关闭intChan管道
	close(intChan)
	// 当channel关闭后,就不能再向channel写数据了
	// intChan <- 200 // 报错:panic: send on closed channel
	fmt.Println("intChan=", intChan) // intChan= 0xc00007a080
	num1 := <-intChan
	// 当channel关闭后,任然可以从channel读取数据
	fmt.Println("num1=", num1) // num1= 100
}

六、channel的遍历

channel支持for-range的方式遍历,注意以下两个细节:

  1. 在遍历时,如果channel没有关闭,则会出现deadlock的错误
  2. 在遍历时,如果channel已经关闭,则会正确遍历数据,遍历完后,就会退出遍历
package main

import "fmt"

func main() {
	var intChan chan int
	intChan = make(chan int, 3)
	// 向管道中写入数据
	intChan <- 100
	num := 200
	intChan <- num
	intChan <- 300
	// 在遍历时,如果channel没有关闭,则会出现deadlock的错误
	// 在遍历时,如果channel已经关闭,则会正确遍历数据,遍历完后,就会退出遍历
	close(intChan)
	for v := range intChan {
		fmt.Println("v=", v)
	}
}

输出结果:

v= 100
v= 200
v= 300
posted @ 2021-06-17 22:02  若雨蚂蚱  阅读(390)  评论(0编辑  收藏  举报