目录
管道(channel)
无缓冲管道
有缓冲管道
需要注意
goroutine与channel实现并发
单向管道
定义单向管道
将双向管道转换为单向管道
单向管道作为函数参数
单向管道的代码示例
select多路复用
案例演示
goroutine panic处理
案例演示
管道(channel)
管道(channel)是 Go 语言中实现并发的一种方式,它可以在多个 goroutine 之间进行通信和数据交换。管道可以看做是一个队列,通过它可以进行先进先出的数据传输,支持并发的读和写。
Go 语言中使用 make 函数来创建一个管道,它的语法如下:
ch := make(chan 数据类型)
其中,数据类型可以是任意的 Go 语言数据类型,例如 int、string 等。创建了一个管道之后,我们就可以在多个 goroutine 之间进行数据传输了。
无缓冲管道
无缓冲管道是指在创建管道时没有指定容量,也就是说,它只能存储一个元素,当一个 goroutine 尝试向管道发送数据时,它会阻塞直到另一个 goroutine 从管道中读取数据。同样的,当一个 goroutine 尝试从管道中读取数据时,它也会阻塞直到另一个 goroutine 向管道中发送数据。
示例代码:
package main
import (
"fmt"
)
func main() {
ch := make(chan int)
go func() {
ch
创建了一个无缓冲管道 ch
,并在一个 goroutine 中向管道中发送了一个整数 10
。在主 goroutine 中,我们通过 从管道中读取数据并打印出来。
有缓冲管道
有缓冲管道是指在创建管道时指定了容量,这时候它可以存储多个元素,但是当管道已满时,尝试向管道发送数据的 goroutine 会被阻塞,直到另一个 goroutine 从管道中读取数据以腾出空间。同样的,当管道为空时,尝试从管道中读取数据的 goroutine 也会被阻塞,直到另一个 goroutine 向管道中发送数据。
示例代码:
package main
import (
"fmt"
)
func main() {
ch := make(chan int, 2)
ch
创建了一个容量为 2 的有缓冲管道 ch
,并在主 goroutine 中向管道中依次发送了整数 10
和 20
。接着,我们依次从管道中读取数据并打印出来。
需要注意
1.管道是有缓冲的,可以通过指定缓冲区大小来控制数据在管道中的流动。如果缓冲区已满,写入操作将会阻塞直到缓冲区有空间;如果缓冲区为空,读取操作将会阻塞直到有数据写入。
2.管道的写入和读取操作都是阻塞的,直到操作完成才会返回。如果需要非阻塞的读写操作,可以使用select
语句进行多路复用。
3.管道可以被关闭,一旦管道被关闭,读取操作将不再阻塞,返回一个零值和一个标识管道已关闭的错误;写入操作将会抛出 panic。为了避免 panic,可以在写入操作之前先检查管道是否已关闭。
4.管道可以用作信号量或同步器,例如使用一个无缓冲的管道实现多个 goroutine 之间的同步。
goroutine与channel实现并发
下面是一个协程与管道实现并发的代码示例,其中使用了两个管道,一个用于发送整数数据,另一个用于接收处理后的数据:
package main
import (
"fmt"
)
func produce(out chan
代码分析:
1.使用 make
函数创建了两个整数类型的管道 ch1
和 ch2
。
2.使用 go
关键字分别启动了函数 produce
和 consume
的协程,其中函数 produce
向管道 ch1
中发送了整数数据,函数 consume
从管道 ch1
中接收数据进行处理,将处理结果发送到管道 ch2
中。
3.在主协程中,使用 range
关键字从管道 ch2
中循环接收处理结果,并将接收到的数据打印出来。
单向管道
在 Go 语言中,有的时候我们会将管道作为参数在多个任务函数间传递,很多时候我们在不同的任务函数中使用管道都会对其进行限制,比如限制管道在函数中只能发送或者只能接收。
定义单向管道
定义一个单向管道可以使用 channel 类型加上箭头运算符(
例如,定义一个只能写入字符串的单向管道可以使用以下语句:
var ch chan
定义一个只能读出字符串的单向管道可以使用以下语句:
var ch
将双向管道转换为单向管道
双向管道可以转换为只读或只写的单向管道,例如,将一个双向管道转换为只读的单向管道可以使用以下语句:
var ch chan string
var chRead
将一个双向管道转换为只写的单向管道可以使用以下语句:
var ch chan string
var chWrite chan
单向管道作为函数参数
单向管道可以作为函数参数来限制管道的读写方向。例如,以下函数接受只读的单向管道作为参数:
func readData(ch
以下函数接受只写的单向管道作为参数:
func writeData(ch chan
单向管道的代码示例
以下是一个使用单向管道的代码示例,该示例将一个双向管道转换为只读和只写的单向管道,并将这些单向管道作为函数参数传递:
package main
import "fmt"
func readData(ch
在上面的代码示例中,定义了一个双向管道 ch,然后将它转换为只读的单向管道 chRead 和只写的单向管道 chWrite,并分别将它们作为 readData 和 writeData 函数的参数传递。在 main 函数中,将 readData 和 writeData 函数放入不同的 goroutine 中运行,以便它们可以并发地读取和写入数据。最后使用 select {} 让主程序保持运行,以便 goroutine 可以继续运行。
select多路复用
在Go语言中,select
语句可以用于多路复用I/O操作,其语法结构类似于switch
语句。它可以同时监视多个管道的读写操作,并在其中一个通道满足读写条件时执行相应的操作。
select
语句的语法如下:
select {
case
在select
语句中,每个case
分支必须是一个通道操作,要么是从通道中读取数据,要么是向通道中写入数据。其中,default
分支是可选的,表示如果没有任何case
语句满足条件,则执行default
语句。
案例演示
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
for i := 1; i
在这个示例中,我们创建了两个通道ch1
和ch2
,并分别向其中写入一些数据。在主函数中,我们使用select
语句监听这两个通道,并在其中一个通道中有数据时输出该数据。由于ch1
的写入间隔为1秒,而ch2
的写入间隔为500毫秒,因此我们可以看到输出的数据是交替出现的。
goroutine panic处理
panic是Go语言中的一种异常处理机制,它的出现是为了让程序在遇到某些不可控制的情况时,能够快速反应,而不是无限期的等待。panic的用法有两种:一种是在程序中显式地调用panic函数,用于处理特定的异常情况;另一种是在程序运行过程中,由于某些不可控制的原因,程序自动抛出panic异常。
案例演示
// 函数
func sayHello() {
for i := 0; i
输出结果: