package main
import("fmt""sync")funcmain(){
kk :=make(chanint,1000)var setwg sync.WaitGroup
var readwg sync.WaitGroup
for i :=1; i <3; i++{
setwg.Add(1)goSet(kk,&setwg)}for i :=1; i <3; i++{
readwg.Add(1)goRead(kk,&readwg)}
setwg.Wait()close(kk)//只要一个 chan 还有未读的数据,即使把它 close 掉,// 你还是可以继续把这些未读的数据消费完,而且bool值为true,之后才是读取零值数据和false
readwg.Wait()//或者下面的实现也可以//for {// if len(kk) == 0 {// close(kk)// readwg.Wait()// break// }//}}funcSet(kk chanint, wg *sync.WaitGroup){defer wg.Done()for i :=1; i <3; i++{
kk <- i
}}funcRead(kk chanint,wg *sync.WaitGroup){defer wg.Done()for{
i, ok :=<-kk
if!ok{
fmt.Println("ok:",ok)break}
fmt.Println(ok)
fmt.Println(i)}}
二,利用两个sync.WaitGroup和通过context的cancel操作实现
package main
import("context""fmt""sync")funcmain(){
kk :=make(chanint,1000)
ctx, cancel := context.WithCancel(context.Background())var setwg sync.WaitGroup
var readwg sync.WaitGroup
for i :=1; i <3; i++{
setwg.Add(1)goSet(kk,&setwg)}for i :=1; i <3; i++{
readwg.Add(1)goRead(kk, ctx,&readwg)}
setwg.Wait()for{iflen(kk)==0{cancel()
readwg.Wait()break}}}funcSet(kk chanint, wg *sync.WaitGroup){defer wg.Done()for i :=1; i <3; i++{
kk <- i
}}funcRead(kk chanint, ctx context.Context,wg *sync.WaitGroup){defer wg.Done()for{select{case<-ctx.Done():returndefault:iflen(kk)>0{
i:=<-kk
fmt.Println(i)}}}}
package main
import("context""fmt""runtime""sync")funcmain(){
kk :=make(chanint,1000)
ctx, cancel := context.WithCancel(context.Background())var setwg sync.WaitGroup
for i :=1; i <3; i++{
setwg.Add(1)goSet(kk,&setwg)}for i :=1; i <3; i++{goRead(kk, ctx)}
setwg.Wait()for{iflen(kk)==0{cancel()break}}for{
fmt.Println("runtime.NumGoroutine()",runtime.NumGoroutine())if runtime.NumGoroutine()==1{break}}}funcSet(kk chanint, wg *sync.WaitGroup){defer wg.Done()for i :=1; i <3; i++{
kk <- i
}}funcRead(kk chanint, ctx context.Context){for{select{case<-ctx.Done():returndefault:iflen(kk)>0{
i:=<-kk
fmt.Println(i)}}}}