乐趣区

关于go:用Golang实现一个简单的生产者消费者模型

工作中常常会遇到一些批量解决数据的需要,如果这些数据的解决没有逻辑上的先后顺序,这时候就正好能够应用 Golang 的并发编程来晋升效率了,话不多说,上代码:

package main

import (
    "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 和内存空间。

如果谋求更高的性能能够考虑一下第三方库,像 panjf2000/ants 的协程池就很成熟,前面有空的话会剖析一下它是如何实现的。

退出移动版