这是我参与2022首次更文挑战的第18天,活动详情查看:2022首次更文挑战
在go语言中,channel是一个协程跟另一个协程通信的媒介,并且这个通信是无锁的。换而言之,一个channel是允许一个协程发送数据给另一个协程的一项技术。默认情况下,channel是双向的,意味着协程可以通过同一个channel来发送或者接收数据,就像下面的图片展示的:
Creating a Channel
在go语言中,一个channel可以使用chan关键字来创建,并且它只可以传输同一种类型的数据,不同类型的数据不允许在同一个channel中传输。
语法:
var Channel_name chan Type
也可以通过使用make()方法来创建一个channel,使用一种简单声明。
channel_name:= make(chan Type)
例子
// Go program to illustrate
// how to create a channel
package main
import "fmt"
func main() {
// Creating a channel
// Using var keyword
var mychannel chan int
fmt.Println("Value of the channel: ", mychannel)
fmt.Printf("Type of the channel: %T ", mychannel)
// Creating a channel using make() function
mychannel1 := make(chan int)
fmt.Println("\nValue of the channel1: ", mychannel1)
fmt.Printf("Type of the channel1: %T ", mychannel1)
}
输出
Value of the channel:
Type of the channel: chan int
Value of the channel1: 0x432080
Type of the channel1: chan int
从一个Channel发送和接收数据
在go语言中,channel跟两个主要原则的一起工作,一个是发送,另一个是接收,这两种操作共同称为通信。<-操作符说明数据是接收或者发送。在channel中,发送和接收操作默认会阻塞住,除非另一侧没有准备好。这允许协程互相同步而不需要明确的锁或者条件变量。
- 发送操作:发送操作是在channel的帮助下,用来从一个协程发送数据给另一个协程。像int,float64,bool类型的值等,可以安全和简单地来通过channel发送,因为它们是被复制的,所以同一个值,没有并发意外的风险。相似的,字符串也可以安全地被传输,因为它们是不可变的。但是像发送指针或者引用,如slice,map等,通过channel是不安全的,因为指针或引用的值可能会被发送或者被接收的协程同时改变,并且结果是不可预知的。因此,当你在channel中使用指针或者引用时,你必须确保同一时刻它们只会被一个协程访问。
Mychannel <- element
上面的语句表明,数据(element)发送到channel(Mychannel),通过<-的帮助。
- 接收操作:接收操作用来接收由发送操作符发送的数据。
element := <-Mychannel
上面的语句表名,element从channel(Mychannel)接收数据。如果接收语句的结果不打算使用的话,这也是一个合法的语句。你也可以这样写一个接收语句:
<-Mychannel
例子
// Go program to illustrate send
// and receive operation
package main
import "fmt"
func myfunc(ch chan int) {
fmt.Println(234 + <-ch)
}
func main() {
fmt.Println("start Main method")
// Creating a channel
ch := make(chan int)
go myfunc(ch)
ch <- 23
fmt.Println("End Main method")
}
输出
start Main method
257
End Main method
关闭channel
你也可以在close()的帮助下来关闭一个channel。这是一个内建方法,设置一个标识表明没有更多的值会发送给这个channel。
语法
close()
你也可以使用range循环来关闭channel。这里,接收者协程可以检查channel是开启或者关闭,通过这种语法:
ele, ok:= <- Mychannel
这里,如果ok的值是true,那么channel是开启的,读操作可以被执行。如果值是false,那就意味着channel是关闭的,读操作就无法执行。
例子
// Go program to illustrate how
// to close a channel using for
// range loop and close function
package main
import "fmt"
// Function
func myfun(mychnl chan string) {
for v := 0; v < 4; v++ {
mychnl <- "GeeksforGeeks"
}
close(mychnl)
}
// Main function
func main() {
// Creating a channel
c := make(chan string)
// calling Goroutine
go myfun(c)
// When the value of ok is
// set to true means the
// channel is open and it
// can send or receive data
// When the value of ok is set to
// false means the channel is closed
for {
res, ok := <-c
if ok == false {
fmt.Println("Channel Close ", ok)
break
}
fmt.Println("Channel Open ", res, ok)
}
}
输出
Channel Open GeeksforGeeks true
Channel Open GeeksforGeeks true
Channel Open GeeksforGeeks true
Channel Open GeeksforGeeks true
Channel Close false
重要知识点
- 阻塞发送和接收:在channel中,当数据发送给一个channel时,这个控制就被阻塞在那个发送操作,直到另一个协程读取了那个channel。同样的,当一个channel从这个协程接收数据时,读语句也会阻塞住,直到另一个协程语句。
- 零值的channel:channel中的零值是nil
- channel中的for循环:一个for循环可以按顺序迭代发送到channel的值,直到它被关闭了。 语法
for item := range Chnl {
// statements..
}
例子
// Go program to illustrate how to
// use for loop in the channel
package main
import "fmt"
// Main function
func main() {
// Creating a channel
// Using make() function
mychnl := make(chan string)
// Anonymous goroutine
go func() {
mychnl <- "GFG"
mychnl <- "gfg"
mychnl <- "Geeks"
mychnl <- "GeeksforGeeks"
close(mychnl)
}()
// Using for loop
for res := range mychnl {
fmt.Println(res)
}
}
输出
GFG
gfg
Geeks
GeeksforGeeks
- channel的长度:在channel中,您可以使用
len()函数来发现channel的长度。这里,length表明channel的缓冲区中的队列的值。 例子
// Go program to illustrate how to
// find the length of the channel
package main
import "fmt"
a
// Main function
func main() {
// Creating a channel
// Using make() function
mychnl := make(chan string, 4)
mychnl <- "GFG"
mychnl <- "gfg"
mychnl <- "Geeks"
mychnl <- "GeeksforGeeks"
// Finding the length of the channel
// Using len() function
fmt.Println("Length of the channel is: ", len(mychnl))
}
输出
Length of the channel is: 4
- channel的容量:在channel中,你可以使用
cap()函数来获取channel的容量。这里,容量表明缓冲区的长度。 例子
// Go program to illustrate how to
// find the capacity of the channel
package main
import "fmt"
// Main function
func main() {
// Creating a channel
// Using make() function
mychnl := make(chan string, 5)
mychnl <- "GFG"
mychnl <- "gfg"
mychnl <- "Geeks"
mychnl <- "GeeksforGeeks"
// Finding the capacity of the channel
// Using cap() function
fmt.Println("Capacity of the channel is: ", cap(mychnl))
}
输出
Capacity of the channel is: 5
- channel中的select和case语句:在go语言中,select语句就像一个没有任何输入参数的switch语句。select语句用在channel来执行由case阻塞提供的多操作中的一个单操作。