go语言中什么是通道(channel)?通道详解
通信介绍
假设有这样一个变量,这个变量需要实现协程间共享。由于协程之间存在隔离性,这时候我们该如何实现呢?
我们可以通过数据库、Redis等类似的组件去实现协程之间共享内存变量。
通过Redis、数据库等方式实现共享。就会面临一个问题,就是对于该变量的竞争,谁先具有执行优先权,修改该变量之后之后,又该如何处理?
这或许就需要用到锁机制,但使用锁就会降低并发。
因此Golang中解决该场景的问题是通过,通信来实现共享变量,而不是通过共享内存来实现共享变量。
通道作用
用于协程之间同步与通信。
通道定义
通道定义通过chan关键字。
// 方式一
var 变量名 chan 值类型
变量名 = make(chan 值类型, 通道长度)
// 方式二
变量名 := make(chan 值类型, 通道长度)
ps:
通道长度指的是通道容量大小。向通道出入数据的数量不能超过容量大小。
示例代码:
package main
import (
"fmt"
_ "sync"
"time"
)
func Show(ch1 chan int) {
val := <-ch1
fmt.Println("通道的值是:", val)
}
func main() {
ch1 := make(chan int, 10)
for i := 0; i < 10; i++ {
go Show(ch1)
ch1 <- i
}
time.Sleep(time.Second * 10)
close(ch1)
fmt.Println("所有的协程已经结束了,主线程可以结束了。")
}
通道操作
通道有三种操作方式。
1.发送数据。
通道名称 <- 传递值
2.接收数据。
值, BooleanVal: = <- 通道名称
当BooleanVal值为false时,表示通道不存在值,为true时,通道存在值。在用非range方式循环取通道值的情况下,可以通过该返回值判断通道是否存在值,避免一直循环通道。
3.关闭通道。
close(通道名称)
通道原理
通道可以理解为一个队列。一端想队列中写入数据,另外一个端从队列中读取数据。同时也遵循队列先进先出的特点。
注意事项
1.向一个通道写入数据之后,就可以关闭通道。在通道关闭之后,仍然能够向通道中读取数据。
2.向通道中写入数据完毕之后,需要关闭通道,否则会出现如下错误信息。
fatal error: all goroutines are asleep - deadlock!
3.循环读取通道数据,推荐使用for k, v :range {}方式进行读取。避免使用for循环。
>方式进行读取。避免使用for循环。rang在循环完通道,会自动退出,不会继续循环。
4.对一个关闭的通道再发送值就会导致panic。
5.对一个关闭的通道进行接收会一直获取值直到通道为空。
6.对一个关闭的并且没有值的通道执行接收操作会得到对应类型的零值。
7.关闭一个已经关闭的通道会导致panic。
8.通道存储的数据,可以是任意类型。
例如,字符串、Boolean、数字、结构体、接口等。
9.通道只能存储单一类型,如果需要存储多类型,推荐定义通道时,使用intearface类型。并且对读取通道值时,部分数据类型需要做断言处理。
相关文章