prime filter

使用并发来做一个素数筛

package main

import "fmt"

func main() {
	ch :=GenerateNatural()
	for i:=0;i<100;i++{
		prime := <-ch                              // 第一个一定是素数
		fmt.Printf("%v: %v\n", i+1, prime)
		ch = primeFliter(ch,prime)
	}
}

// 生成一个自然数列
func GenerateNatural() chan int {
	ch := make(chan int)
	go func() {
		for i := 2; ; i++ {
			ch <- i
		}
	}()
	return ch
}

// 根据prime过滤,过滤后的第一个一定是素数
func primeFliter(in <- chan int,prime int) chan int{
	out := make(chan int)
	go func() {
		for {
			if i:=<-in;i%prime!=0{
				out <- i
			}
		}
	}()
	return out
}

GenerateNatural和PrimeFilter函数内部都启动了新的Goroutine,当main函数不再使用管道时后台Goroutine有泄漏的风险。可以通过context包来避免这个问题,下面是改进的素数筛实现:

package main

import (
	"context"
	"fmt"
)

func GenerateNatural(ctx context.Context) chan int {
	ch := make(chan int)
	go func() {
		for i := 2; ; i++ {
			select {
			case <-ctx.Done():
				return
			case ch <- i:
			}
		}
	}()
	return ch
}

func primeFilter(ctx context.Context, in <-chan int, prime int) chan int {
	out := make(chan int)
	go func() {
		for {
			if i := <-in; i%prime != 0 {
				select {
				case <-ctx.Done():
					return
				case out <- i:
				}
			}
		}
	}()
	return out
}

func main() {

	ctx, cancel := context.WithCancel(context.Background())
	ch := GenerateNatural(ctx)
	for i := 0; i < 1000; i++ {
		prime := <-ch
		fmt.Printf("%v: %v\n", i+1, prime)
		ch = primeFilter(ctx, ch, prime)
	}

	cancel()   // main函数完成时,调用cancel(),通知后台goroutine退出,即ctx.Done收到信号
}