package main
import("fmt""sync""time")funcmain(){wghelloChannels()}// 加waitgroup的channelfuncwghelloChannels(){var wg sync.WaitGroup
//开启N个后台打印线程for i :=0; i <10; i++{
wg.Add(1)//增加等待事件的个数gofunc(){defer wg.Done()//完成一个事件
fmt.Println("你好,世界")}()}//等待N个后台线程完成
wg.Wait()//等待全部事件完成
fmt.Println("exit")}funchelloChannel(){
done :=make(chanint,1)//带缓存的管道gofunc(){
time.Sleep(3* time.Second)
fmt.Println("hello world")
done <-1}()<-done
fmt.Println("exit")}// 对于带缓冲的 Channel,对于 Channel 的第 K 个接收完成操作发生在第 K+C 个发送操作完成之前,其中 C 是 Channel 的缓存大小。funchelloChannels(){
done :=make(chanint,10)//开启N个后台打印线程for i :=0; i <cap(done); i++{gofunc(i int){
fmt.Println("你好 世界", i)
done <-1}(i)}//等待N个后台线程完成for i :=0; i <cap(done); i++{<-done
}
fmt.Println("EXIT")}
三、 并发的安全退出
package main
import("fmt""sync""time")funcmain(){//3.现在每个工作者并发体的创建、运行、暂停和退出都是在 main 函数的安全控制之下了。
cancel :=make(chanbool)var wg sync.WaitGroup
for i :=0; i <10; i++{
wg.Add(1)goworkerwg(&wg, cancel)}
time.Sleep(time.Second)close(cancel)
wg.Wait()//2.我们通过 select 和 default 分支可以很容易实现一个 Goroutine 的退出控制://cancel := make(chan bool)//go worker(cancel)//time.Sleep(5 * time.Millisecond)//cancel <- true//1.当多个管道均可操作时,select会随机选择一个管道//ch := make(chan int)//go func() {// for {// select {// case ch <- 0:// case ch <- 1:// }// }//}()//for v := range ch {// fmt.Println(v)//}}// 3.现在每个工作者并发体的创建、运行、暂停和退出都是在 main 函数的安全控制之下了。funcworkerwg(wg *sync.WaitGroup, cancel chanbool){defer wg.Done()for{select{default:
fmt.Println("hello")case<-cancel:return}}}// 2.我们通过 select 和 default 分支可以很容易实现一个 Goroutine 的退出控制:funcworker(cancel chanbool){for{select{default:
fmt.Println("hello")//正常退出case<-cancel://退出}}}
四、生产者消费者
package main
import("fmt""os""os/signal""syscall")funcmain(){
ch :=make(chanint,64)goproducer(5, ch)goproducer(3, ch)goconsumer(ch)//1. 运行一定时间退出//time.Sleep(1 * time.Second)//2.main函数保持阻塞状态,只有用户输入 ctrl-c 才真正退出
sig :=make(chan os.Signal,1)//signa l.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)//这两个等价
fmt.Printf("quit(%v)\n",<-sig)}// 生产者:生成factor的整数列funcproducer(factor int, out chan<-int){for i :=0;; i++{
out <- i * factor
}}// 消费者funcconsumer(in <-chanint){for v :=range in {
fmt.Println(v)}}
五、素数筛
package main
import"fmt"funcmain(){
ch :=GenerateNature()for i :=0; i <100; i++{//100次迭代循环
prime :=<-ch //新出现素数
fmt.Printf("%v:%v\n", i+1, prime)
ch =PrimeFilter(ch, prime)//基于新素数构造的新的过滤器}}// 返回生成自然数序列的管道 :2 3 4 ...funcGenerateNature()chanint{
ch :=make(chanint)gofunc(){for i :=2;; i++{
ch <- i
}}()return ch
}// 管道过滤器,删除能被素数整除的数funcPrimeFilter(in <-chanint, prime int)chanint{
out :=make(chanint)gofunc(){for{if i :=<-in; i%prime !=0{
out <- i
}}}()return out
}
六、context完善同步
package main
import("context""fmt""sync")/*
标准库增加了一个 context 包,用来简化对于处理单个请求的多个 Goroutine 之间与请求域的数据、超时和退出等操作,
我们可以用 context 包来重新实现前面的线程安全退出或超时的控制:
*/funcmain(){//2.context 素数筛
wg := sync.WaitGroup{}//通过context控制后台 goroutine状态
ctx, cancel := context.WithCancel(context.Background())
wg.Add(1)
ch :=generateNaturecontext(ctx,&wg)//自然序数列:2,3,4for i :=0; i <100; i++{
prime :=<-ch //出现新的素数
fmt.Printf("%v:%v\n", i+1, prime)
wg.Add(1)
ch =primeFiltercontext(ctx, ch, prime,&wg)//基于新素数构造的新过滤器}cancel()
wg.Wait()//1.我们可以用 context 包来重新实现前面的线程安全退出或超时的控制://ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)//var wg sync.WaitGroup//for i := 0; i < 10; i++ {// wg.Add(1)// go workercontext(ctx, &wg)//}//time.Sleep(time.Second)当调用cancel()函数时,它会向done通道发送一个信号,表示相关的上下文已经被取消,并且传入了一个错误值(如果有的话)。//cancel()//wg.Wait()}// 2.context 素数筛// 返回生成自然数序列的管道: 2, 3, 4, ...funcgenerateNaturecontext(ctx context.Context, wg *sync.WaitGroup)chanint{
ch :=make(chanint)gofunc(){defer wg.Done()deferclose(ch)for i :=2;; i++{select{case<-ctx.Done():returncase ch <- i:}}}()return ch
}// 2.context 素数筛// 管道过滤器: 删除能被素数整除的数funcprimeFiltercontext(ctx context.Context, in <-chanint, prime int, wg *sync.WaitGroup)chanint{
out :=make(chanint)gofunc(){defer wg.Done()deferclose(out)for i :=range in {if i%prime !=0{select{case<-ctx.Done():returncase out <- i:}}}}()return out
}// 1.我们可以用 context 包来重新实现前面的线程安全退出或超时的控制:funcworkercontext(ctx context.Context, wg *sync.WaitGroup)error{defer wg.Done()for{select{default:
fmt.Println("hello")//在与该上下文相关的goroutine中,通过检查ctx.Done()通道来捕获取消信号。当cancel()函数被调用后,<-ctx.Done()将会接收到这个信号,case<-ctx.Done():return ctx.Err()}}}