使用channel和sync.Mutex可实现Go并发队列。带缓冲channel支持多生产者消费者,代码简洁高效;自定义slice+mutex+cond适用于需阻塞或复杂控制的场景。

在Go语言中实现并发队列,核心是利用 channel 和 goroutine 的天然并发支持。Golang的channel本身就是线程安全的,非常适合用来构建高效的并发队列,无需手动加锁。下面介绍几种常见的实现方式和使用场景。
使用带缓冲的Channel作为并发队列
最简单且高效的方式是使用带缓冲的channel。它天然支持多个生产者和消费者并发操作。
示例:package mainimport ( "fmt" "time" )
func main() { // 创建一个容量为5的整型队列 queue := make(chan int, 5)
// 启动消费者 go func() { for num := range queue { fmt.Printf("消费: %d\n", num) time.Sleep(100 * time.Millisecond) // 模拟处理时间 } }() // 生产者发送数据 for i := 1; i <= 10; i++ { queue <- i fmt.Printf("生产: %d\n", i) } close(queue) // 关闭channel,通知消费者结束 time.Sleep(2 * time.Second) // 等待消费完成}
这种方式适用于大多数场景,代码简洁,性能好。
使用sync.Mutex保护的Slice队列(自定义结构)
如果需要更复杂的队列行为(如优先级、超时、动态扩容),可以基于slice + mutex实现。
立即学习“go语言免费学习笔记(深入)”;
示例:package mainimport ( "container/list" "fmt" "sync" )
type Queue struct { data list.List mu sync.Mutex cond sync.Cond }
func NewQueue() *Queue { q := &Queue{ data: list.New(), } q.cond = sync.NewCond(&q.mu) return q }
func (q *Queue) Push(value interface{}) { q.mu.Lock() q.data.PushBack(value) q.mu.Unlock() q.cond.Signal() // 唤醒等待的消费者 }
func (q *Queue) Pop() interface{} { q.mu.Lock() defer q.mu.Unlock()
for q.data.Len() == 0 { q.cond.Wait() // 阻塞直到有数据 } e := q.data.Front() q.data.Remove(e) return e.Value}
dmSOBC SHOP网店系统下载dmSOBC SHOP网店系统由北京时代胜腾信息技术有限公司(http://www.webzhan.com)历时6个月开发完成,本着简单实用的理念,商城在功能上摒弃了外在装饰的一些辅助功能,尽可能的精简各项模块开发,做到有用的才开发,网店V1.0.0版本开发完成后得到了很多用户的使用并获得了好评,公司立即对网店进行升级,其中包括修正客户提出的一些意见和建议,现对广大用户提供免费试用版本,如您在使用
func (q *Queue) Len() int { q.mu.Lock() defer q.mu.Unlock() return q.data.Len() }
这种实现适合需要阻塞读取或精细控制的场景。sync.Cond用于避免忙等,提升效率。
多生产者-多消费者模型实战
实际项目中常遇到多个goroutine同时读写队列的情况。下面是一个完整例子:
// 启动多个生产者 for i := 0; i < 3; i++ { go func(id int) { for j := 0; j < 5; j++ { queue <- fmt.Sprintf("消息-%d-%d", id, j) time.Sleep(50 * time.Millisecond) } }(i) }// 启动多个消费者 for i := 0; i < 2; i++ { go func(id int) { for msg := range queue { fmt.Printf("消费者%d处理: %s\n", id, msg) time.Sleep(100 * time.Millisecond) } }(i) }
注意:需确保所有生产者完成后关闭channel,否则消费者会一直阻塞。可以用sync.WaitGroup协调。
基本上就这些。用channel是最推荐的方式,足够安全又高效。只有在标准channel无法满足需求时,才考虑用锁+slice的方案。关键是理解Go的并发哲学:通过通信共享内存,而不是通过共享内存通信。










