go通过chan和go func进行并发控制

原文:

1. 需求

启动一个goroutine,将1-10000的数字放入chan中
启动4个goroutine从chan中读取数字,并计算是不是素数
是素数就讲结果放入结果chan中
最后遍历结果chan,打印素数集合

2. 思路

这道题思路很简单,首先明确一个点就是这个需求有三种类型的goroutine:

第一种类型就是生产者,它主要负责数据的生产;
第二种类型就是消费者,他主要负责消费数据做加工;
第三种类型就是main goroutine,他主要负责调度这些goroutine并且等待他们退出。
明确思路之后我们在深入分析下,这个需求需要三个chan:

第一个就是生产者和消费者之间的通信是需要一个chan的,这个chan就是生产者生产数字放到chan中,消费者从chan取出数字。
第二个就是消费者计算完素数之后结果得放入一个chan中,这个chan需要和main goroutine通信,因为main goroutine需要遍历打印这些素数;
最后一个就是main goroutine需要等待所有消费goroutine的退出,因为我不知道消费者什么时候结束,所以也需要一个chan和main goroutine通信。
因此这个需求需要三种类型的goroutine和三种类型的chan。

3.代码实现

package main

import (
	"fmt"
)

func main()  {
	prochan := make(chan int, 10000)
	primeChan := make(chan int, 5000)
	exitChan := make(chan bool, 4)

	// 1.produce num
	go producer(prochan)

	// 2.consume num
	for i := 0; i < 4; i++ {
		go consumer(prochan, primeChan, exitChan)
	}

	// 3.up a g to wait consumers over
	go func() {
		for i := 0; i < 4; i++ {
			<- exitChan
		}
		close(primeChan)
	}()
        defer close(exitChan)

	// 4.main goroutine print the result
	for v := range primeChan {
		fmt.Println("main goroutine recv prime number is: ", v)
	}

	fmt.Println("main goroutine is over.")
}

// producer
func producer(proChan chan int)  {
	fmt.Println("Producer goroutine 开始生产数据啦!")
	for i := 1; i <= 10000; i++ {
		proChan <- i
	}
	close(proChan)
	fmt.Println("Producer goroutine 开始生产结束啦!")
}

// consumer
func consumer(proChan chan int, primeChan chan int, exitChan chan bool)  {
	fmt.Println("Consumer goroutine 开始消费数据啦!")
	for{
		// 1.get num
		num, ok := <- proChan
		if !ok {
			break // producer closed chan
		}
		// 2.if is prime number, add to prime chan
		if isPrimeNum(num) {
			primeChan <- num
		}
	}

	// 3.the g is over
	exitChan <- true

	fmt.Println("Consumer goroutine 退出啦!")

}

func isPrimeNum(num int) bool {
	if num == 1 {return true}
	for i := 2; i < num; i++ {
		if num % i == 0 {return false}
	}
	return true
}

posted on 2022-12-21 15:59  进击的davis  阅读(170)  评论(0编辑  收藏  举报

导航