package main

import (
	"fmt"
	"time"
)

/*
统计1---20000的数字中,哪些是素数?

本例中使用并发的方式,将统计素数的任务分配给多个(4个)goroutine去完成。

设计三个通道 intChan,primeChan,exitChan
intChan,
primeChan,
exitChan
*/


//向intChan总放入1--8000个数
func putNum(intChan chan int){
	for i := 1; i <=8000 ; i++ {
		intChan<-i


	}
	//关闭intChan
	close(intChan)
}


/*
从intChan取出数据,并判断是否是素数,如果是就是放到到primeChan通道中


*/

func primeNum(intChan chan int,primeChan chan int,exitChan chan bool){
	var flag bool   //判断是否是素数的标记
	for {
		time.Sleep(time.Millisecond*10)
		num,ok:=<-intChan

		if !ok{  //intChan中取完数据后,就是关闭
			break
		}
		flag=true  //假设是素数
		//判断num是不是素数
		for i := 2; i <num ; i++ {
			if num%i==0{ //说明该num不是素数
				flag=false
				break
			}

		}

		if flag{
			//如果flag为真,说明这个数是素数,把他放入primeChan中
			primeChan<-num
		}




	}

	fmt.Println("有一个primeNum协程因为取不到数据,退出")
	//这里我们还不能关闭primeChan
	//向exitChan写入true
	exitChan<-true
}


func main() {
	intChan:=make(chan int,10000)
	primeChan:=make(chan int,2000)  //放入素数

	//标识退出的管道
	exitChan:=make(chan bool,4)  //4个

	//开启一个协程,向intChan放入数字
	go putNum(intChan)

	//开启4个协程,从intChan取出数据,并判断是否是素数,如果是,就是放入primeChan中
	for i := 0; i <4 ; i++ {
		go primeNum(intChan,primeChan,exitChan)


	}

	//这里是主线程,等待4个任务都是处理完毕后,在结束主程序
	go func() {
		for i := 0; i < 4; i++ {
			<-exitChan

		}
		// 当我们从exitchan中取出4个结果,就是可以关闭primechan通道了
		close(primeChan)
	}()

	//遍历我们的primeChan,把结果取出
	for  {
		res,ok:=<-primeChan
		if!ok{
			break
		}
		fmt.Printf("素数是=%d\n",res)

	}

	fmt.Println("程序结束....")


}