用Golang实现一个简单的生产者/消费者模型

工作中经常会遇到一些批量处理数据的需求,如果这些数据的处理没有逻辑上的先后顺序,这时候就正好可以使用Golang的并发编程来提升效率了,话不多说,上代码:

package mainimport ( "fmt" "sync" )func main() { //初始化管道来接收任务数据 ch := make(chan int, 10000) //所有任务执行完毕才结束进程 wg := &sync.WaitGroup{} //用来控制协程数量,超过50个会阻塞 pool := make(chan struct{}, 50) //任务数量 count := 1000 go producer(ch, count, wg) consumer(ch, pool, wg) wg.Wait() fmt.Println("任务处理完毕") }//生产者 func producer(ch chan int, count int, wg *sync.WaitGroup) { defer close(ch) wg.Add(count) for i := 0; i < count; i++ { ch <- i fmt.Println("任务", i, "生产完毕") } }//消费者 func consumer(ch chan int, pool chan struct{}, wg *sync.WaitGroup) { for c := range ch { pool <- struct{}{} <-pool go handler(c, wg) } }//具体消费逻辑 func handler(c int, wg *sync.WaitGroup) { defer wg.Done() fmt.Println("任务", c, "消费完毕") }

  • producer是生产者,里面批量生产业务数据,放到一个有缓冲管道里
  • consumer是消费者,起多个协程消费管道里的数据,而协程的数量自然需要控制,怎么控制呢?通过pool这个有缓冲管道,机制就是每消费一条数据就往pool里发送一条数据,消费完读出,这样同时最多有50个任务同时在处理,超过则会阻塞等待其他协程处理完毕。
  • wg用来等待子协程处理完毕
这种模型的优势在于应用简单、容易控制,goroutine本身很轻便,仅损耗极少许的内存空间和调度,在处理数据量级不大、业务逻辑不太复杂的情况应用是足够的,但是数据量级在几百万、几千万的时候还是这样频繁的创建goroutine,会浪费大量调度goroutine和内存空间。
【用Golang实现一个简单的生产者/消费者模型】如果追求更高的性能可以考虑一下第三方库,像panjf2000/ants的协程池就很成熟,后面有空的话会分析一下它是如何实现的。

    推荐阅读