在本教程中,您将学习Go语言中的Channel概念。Go语言中的Channel与我们之前教程中讨论的Go语言中的Goroutine相关。您可以先参考Go routine,然后才能理解本教程将要讨论的Channel。
在Go语言中,Channel是一种允许Goroutine之间共享数据的机制。Goroutine允许Go程序中的活动并发执行,这些活动在Goroutine之间共享数据或资源。Go语言支持成千上万的Goroutine在执行过程中共享数据或资源以实现并发。(我们已经在Goroutine教程中讨论过这一点)

Goroutine A将一些数据写入Channel,Goroutine B从同一个Channel读取数据。因此,Channel(路径)有助于Goroutines之间的数据传输或通信。
为了更好地理解Channel的概念,我们将简要回顾一下Goroutine中发生的事情。
让我们用我们在Goroutine教程中讨论的同一个例子来理解。
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("Go program starts")
msg :="learn eTutorial"
go func(){ //anonymous function
fmt.Println(msg)
}()
msg = "hello users"
fmt.Println("Go program ends")
time.Sleep(100 * time.Millisecond)
}
上面给出的程序包含两个代码块。

这两个代码段独立执行。由于main()和hello()函数Goroutine的独立执行,出现了以下问题:
使用新的keyword chan在Go中声明Channel。
声明语法
var <variable name> chan <data type>

这里c是一个通道类型的变量,用chan关键字声明,数据类型为整数(int)。
注意: 声明时Channel的默认值为nil,与我们在Goroutine中讨论的一样。
在Go语言中,Channel是允许我们Go程序中特定Goroutines之间有效通信的结构。Go Channel的概念自1970年代中期就存在了。
让我们看看如何实例化一个Channel并将其用于不同Goroutines之间的通信。
我们将逐步理解。
msgs的新Channel。make”关键字,后跟chan关键字及其声明的type。在给定的程序中,数据类型是整数。发送运算符(<- ),用于向此Channel发送值。go SendMsg(msgs)发送到Channel的。变量msg。这会在输出中显示。这是一个简单的整数Channel示例。注意: Channel使用make函数创建,该函数指定chan关键字和Channel的元素类型。
当我们创建一个未指定Channel大小的Channel时,它被称为未缓冲Channel。您将在下一节中学习。
package main
import (
"fmt"
)
func SendMsg(c chan int){
c <-0
}
func main() {
fmt.Println("Learn eTutorial")
msgs := make(chan int) // instantiating a channel
defer close(msgs)
go SendMsg(msgs)
msg := <-msgs
fmt.Println(msg)
}
输出
Learn eTutorial 0
根据数据在Goroutines之间的传输方式,Channel有两种类型。它们是:

让我们考虑上面描述的相同程序,但唯一的区别是我们创建了一个字符串数据类型的Channel。
为了更好地理解相同的概念,对上面给出的代码进行了一些修改:
package main
import (
"fmt"
"time"
)
func SendMsg(c chan string){
fmt.Println("start Goroutine execution")
time.Sleep(1 * time.Second)
c <-"hello world"
fmt.Println("finished Goroutine execution")
}
func main() {
fmt.Println("Learn eTutorial")
msgs := make(chan string) //created channel of string type.
defer close(msgs)
go SendMsg(msgs)
go SendMsg(msgs)
msg := <-msgs
fmt.Println(msg)
}
输出
Learn eTutorial start Goroutine execution start Goroutine execution finished Goroutine execution hello world
func SendMsg(c chan string){
fmt.Println("start Goroutine execution")
time.Sleep(1 * time.Second)
c <-"hello world"
fmt.Println("finished Goroutine execution")
}
在这部分代码中,定义了两个打印语句(“开始Goroutine执行”)和(“完成Goroutine执行”)。Sleep语句允许Goroutine睡眠几秒钟。在向Channel发送操作,即c <- "hello world"之后,打印出Goroutine执行已完成。
还重复了go SendMsg(msgs)语句。有两个Goroutines正在尝试发送到同一个Channel。
在上述程序中,只有一个接收语句 msg := <-msgs 到Channel,因此只有一个Goroutine预计会完成其执行。只有一个Goroutine会执行并打印最后的打印语句。
第二个Goroutine不会完成其执行,被阻塞在main函数中。程序将在第二个Goroutine完成执行之前终止。
为了避免阻塞行为,我们指定了Channel的大小。当一个Channel在创建时指定了其大小时,它被称为缓冲Channel。
语法
Buffered channel: = make (chan datatype, size)
示例
msgs: = make (chan string, 2)
通过将其更改为缓冲Channel,发送操作,c <-"hello world" 只会在Goroutines中阻塞。
import (
"fmt"
"time"
)
func SendMsg(c chan string){
fmt.Println("start Goroutine execution")
time.Sleep(1 * time.Second)
c <-"hello world"
fmt.Println("finished Goroutine execution")
}
func main() {
fmt.Println("Learn eTutorial")
msgs := make(chan string,2) //created channel of string type.
defer close(msgs)
go SendMsg(msgs)
go SendMsg(msgs)
msg := <-msgs
fmt.Println(msg)
time.Sleep(1 * time.Second)
}
输出
Learn eTutorial start Goroutine execution start Goroutine execution finished Goroutine execution hello world finished Goroutine execution
在最后提供了一个sleep()语句,因为不能保证第二个Goroutine在第一个Goroutine退出之前完成。
从输出中可以清楚地看到,第一个和第二个Goroutine开始执行,同样,两者都完成。
当我们在没有可用接收者时不想让Channel语句阻塞时,可以使用缓冲Channel。添加缓冲区允许我们等待一些接收者被释放,而不会阻塞发送代码。
Channel提供的基本操作是读和写。读写Channel用左箭头<-表示。

注意: 相同的运算符也表示Channel中的发送/接收操作。

这里Channel发送和接收数据。让蓝色的圆圈代表一个字符串“hello world”消息。
发送操作:这表示消息“hello world”(数据)被发送到创建为c的Channel。(上面各节已讨论过Channel的创建)。
c <-"hello world"
接收操作:在此操作中,Goroutine A发送到Channel的消息由另一个Goroutine B接收,通过创建一个名为msg的新变量。
msg := <-c
package main
import (
"fmt"
"time"
)
func myfunc(c chan string) {
fmt.Println("start Goroutine execution")
time.Sleep(1 * time.Second)
c <-"hello world" //send msg hello world to channel c
fmt.Println("finished Goroutine execution")
}
func main() {
fmt.Println("start Main method")
// Creating a channel
c := make(chan string)
go myfunc(c)
msg := <-c //receive msg helloworld from channel c
fmt.Println(msg)
fmt.Println("End Main method")
}
输出
start Main method start Goroutine execution finished Goroutine execution hello world End Main method