Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
一、题目描述
使用goroutine和channel实现生产者消费者模型。
二、思路分析
- 开启两个channel,一个作为任务队列,一个阻塞主线程,等待协程任务完成。
- 两种go协程,一个协程作为生产者向任务队列中送入任务数据,多个消费者协程从任务队列中获取任务,执行任务,完成任务后向done channel中送入数据,表示任务完成。
- 生产者协程向通道中送入生成任务,结束时关闭通道。
- 消费者协程开启for循环不断获取通道中的任务,如果通道中为空,则break循环,从循环中退出,并且向done通道中写入数据,表示该协程任务已完成
- 主线程开启一个生产者协程和多个消费者协程,并且从done通道中获取数据,如果数据为准备就绪,主协程阻塞,等待消费者协程完成任务。
三、AC 代码
package main
import "fmt"
func Producer(ch chan int) {
defer close(ch)
for i := 0; i < 10; i++ {
ch <- i
}
}
func Consumer(id int, ch chan int, done chan bool) {
for {
value, ok := <-ch
if ok {
fmt.Printf("id %d,value %d \n", id, value)
} else {
break
}
}
done <- true
}
func main() {
ch := make(chan int, 3)
conum := 2
done := make(chan bool, conum)
for i := 0; i < conum; i++ {
go Consumer(i, ch, done)
}
go Producer(ch)
for i := 0; i < conum; i++ {
<-done
}
}
使用waitgroup
func producer(ch chan int) {
defer close(ch)
for i := 0; i < 10; i++ {
ch <- i
}
}
func waitconsumer(id int, ch chan int, wg *sync.WaitGroup) {
for {
if value, ok := <-ch; ok {
fmt.Printf("ID:%d,task:%d\n", id, value)
} else {
break
}
}
wg.Done()
}
func main() {
var wg sync.WaitGroup
ch := make(chan int, 3)
go producer(ch)
conum := 2
wg.Add(conum)
for i := 0; i < conum; i++ {
go waitconsumer(i, ch, &wg)
}
wg.Wait()
}
四、总结
生产者消费者模型,需要考虑阻塞主协程可以使用sync.waitgroup等待任务完成,也可以开启一个等待任务完成的通道,阻塞主线程。