go channel信道

channel 信道

在go中是一种特殊的类型,在任何时候,同时只能有一个goroutine访问通道进行发送和获取数据。goroutine间通过通道就可以通信。
channel类似队列先进先出

  1. channel本身是一个队列,先进先出
  2. 线程安全,不需要加锁
  3. 本身是有类型的,string,int等,如果要存多种类型,定义成interface类型
  4. channel是引用类型,必须make之后才能使用,一旦make,他的容量就确定了,不会动态增加,他跟map和slice不一样
特点
  1. 一旦初始化容量,就不会改变了。
  2. 当写满时,不可以写,取空时,不可以取
  3. 发送将持续阻塞直到数据被接收
    把数据往通道中发送时,如果接收方一直都没有接收,那么发送操作将持续阻塞。Go程序运行时能智能的发现一些永远无法发送成功的语句并做出提示
  4. 接收将持续阻塞直到发送方发送数据。
    如果接收方接收时,通道中没有发送方发送数据,接收方也会发生阻塞,直到发送方发送数据为止
  5. 每次接收一个元素
package main

import (
	"fmt"
)

func main() {

	//演示一下管道的使用
	//1. 创建一个可以存放3个int类型的管道
	var intChan chan int
	intChan = make(chan int, 3)

	//2. 看看intChan是什么
	fmt.Printf("intChan 的值=%v intChan本身的地址=%p\n", intChan, &intChan)

	//3. 向管道写入数据
	intChan <- 10
	num := 211
	intChan <- num
	intChan <- 50
	// //如果从channel取出数据后,可以继续放入
	<-intChan
	intChan <- 98 //注意点, 当我们给管写入数据时,不能超过其容量

	//4. 看看管道的长度和cap(容量)
	fmt.Printf("channel len= %v cap=%v \n", len(intChan), cap(intChan)) // 3, 3

	//5. 从管道中读取数据

	var num2 int
	num2 = <-intChan
	fmt.Println("num2=", num2)
	fmt.Printf("channel len= %v cap=%v \n", len(intChan), cap(intChan)) // 2, 3

	//6. 在没有使用协程的情况下,如果我们的管道数据已经全部取出,再取就会报告 deadlock

	num3 := <-intChan
	num4 := <-intChan

	//num5 := <-intChan

	fmt.Println("num3=", num3, "num4=", num4 /*, "num5=", num5*/)

}

注意接口类型的channel
package main
import (
	"fmt"
)

type Cat struct {
	Name string
	Age int
}

func main() {

	//定义一个存放任意数据类型的管道 3个数据
	//var allChan chan interface{}
	allChan := make(chan interface{}, 3)

	allChan<- 10
	allChan<- "tom jack"
	cat := Cat{"小花猫", 4}
	allChan<- cat

	//我们希望获得到管道中的第三个元素,则先将前2个推出
	<-allChan
	<-allChan

	newCat := <-allChan //从管道中取出的Cat是什么?

	fmt.Printf("newCat=%T , newCat=%v\n", newCat, newCat)
	//下面的写法是错误的!编译不通过
	//fmt.Printf("newCat.Name=%v", newCat.Name)
	//使用类型断言
	a := newCat.(Cat)
	fmt.Printf("newCat.Name=%v", a.Name)
}

channel的关闭:close()

关闭之后不能再写入,只能读。
只能由发送者执行这句代码

接收管道数据
  1. 阻塞接收数据,执行该语句时将会阻塞,直到接收到的数据并赋值给data变量。
    例子:data := <-ch
  2. 非阻塞接收数据(有问题,还是会报错deadlock)
    例子:data,ok := <-ch
    data: 表示接收到的数据。未接收到数据时,data为通道类型的零值
    ok:表示是否接收到数据
    非阻塞的通道接收方法可能造成高的CPU占用,因此使用非常少。如果需要实现接收超时检测,可以配合select和计时器channel进行。
  3. 接收任意数据,忽略接收的数据
    例子:<-ch
    执行该语句时将会发送阻塞,直到接收到数据,但接收的数据会被忽略。
  4. 循环接收
    通道的数据接收可以借用for range语句进行多个元素的接收操作
    例子
    for data := range ch{
    }
    通道ch是可以进行遍历的,遍历的结果就是接收到的数据。数据类型就是通道的数据类型。通过for遍历获得的变量只有一个(遍历管道之前要先关闭管道,不然会出现deadlock的错误)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值