管道和消息队列是 go 中用于 goroutine 通信的原语。管道是无缓冲通道,立即传递数据;消息队列是缓冲通道,允许存储多个消息。实战案例中,管道可用于并行处理任务,如将一组任务发送到管道并使用 goroutine 池并行处理。
Go 中的管道与消息队列
在 Go 中,管道和消息队列是用于 goroutine 之间通信的两个基本原语。
管道
立即学习“go语言免费学习笔记(深入)”;
管道是无缓冲的通信通道,数据会立即从写入端传递到读取端。管道通常用于在 goroutine 之间传递小块数据。
创建管道:
package main import "fmt" func main() { // 创建一个管道 ch := make(chan int) // 写入数据 ch <- 42 // 读取数据 v := <-ch fmt.Println(v) // 输出 42 }
消息队列
消息队列是一种缓冲的通信通道,允许在写入端和读取端之间存储多个消息。这使得 goroutine 可以按自己的节奏发送和接收消息,而不必担心丢失或阻塞。
使用内置的 sync.Mutex 和 sync.Cond 创建一个简单的消息队列:
package main import ( "fmt" "sync" "time" ) func main() { // 创建一个消息队列 var ( queue = []int{} mu sync.Mutex cond sync.Cond ) // 启动一个生产者 goroutine go func() { for { mu.Lock() queue = append(queue, 42) cond.Signal() mu.Unlock() time.Sleep(time.Second) } }() // 启动一个消费者 goroutine go func() { for { mu.Lock() for len(queue) == 0 { cond.Wait() } v := queue[0] queue = queue[1:] mu.Unlock() fmt.Println(v) // 输出 42 } }() // 等待 goroutine 退出 time.Sleep(time.Second * 5) }
实战案例:并行处理任务
管道或消息队列可以用于并行处理任务。以下是一个示例,说明如何使用管道并行处理一组任务:
package main import ( "fmt" "sync" ) func main() { // 定义任务 tasks := []int{1, 2, 3, 4, 5} // 创建管道 ch := make(chan int) // 启动 goroutine 池来处理任务 var wg sync.WaitGroup for i := 0; i < 4; i++ { wg.Add(1) go func(ch chan int) { for task := range ch { fmt.Println(task) } wg.Done() }(ch) } // 将任务发送到管道 for _, task := range tasks { ch <- task } // 关闭管道 close(ch) // 等待 goroutine 池完成 wg.Wait() }