func worker(wg *sync.WaitGroup, cannel chan bool) { defer wg.Done() for { select { default: fmt.Println("hello") case <-cannel: return } }}func main() { cancel := make(chan bool) var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go worker(&wg, cancel) } time.Sleep(time.Second) close(cancel) wg.Wait()}现在每个工作者并发体的创建、运行、暂停和退出都是在main()函数的安全控制之下了 。
1.6.8 context包在Go 1.7发布时,标准库增加了一个context包,用来简化对于处理单个请求的多个Goroutine之间与请求域的数据、超时和退出等操作,官方有博客文章对此做了专门介绍 。我们可以用context包来重新实现前面的线程安全退出或超时的控制:
func worker(ctx context.Context, wg *sync.WaitGroup) error { defer wg.Done() for { select { default: fmt.Println("hello") case <-ctx.Done(): return ctx.Err() } }}func main() { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go worker(ctx, &wg) } time.Sleep(time.Second) cancel() wg.Wait()}当并发体超时或main主动停止工作者Goroutine时,每个工作者都可以安全退出 。
Go语言是带内存自动回收特性的,因此内存一般不会泄漏 。在前面素数筛的例子中,GenerateNatural和PrimeFilter()函数内部都启动了新的Goroutine,当main()函数不再使用通道时,后台Goroutine有泄漏的风险 。我们可以通过context包来避免这个问题,下面是改进的素数筛实现:
// 返回生成自然数序列的通道: 2, 3, 4, ...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() { // 通过Context控制后台Goroutine状态 ctx, cancel := context.WithCancel(context.Background()) ch := GenerateNatural(ctx) // 自然数序列:2, 3, 4, ... for i := 0; i < 100; i++ { prime := <-ch // 新出现的素数 fmt.Printf("%v: %vn", i+1, prime) ch = PrimeFilter(ctx, ch, prime) // 基于新素数构造的过滤器 } cancel()}当main()函数完成工作前,通过调用cancel()来通知后台Goroutine退出,这样就避免了Goroutine的泄漏 。
并发是一个非常大的主题,这里只展示几个非常基础的并发编程的例子 。官方文档也有很多关于并发编程的讨论,国内也有专门讨论Go语言并发编程的书籍 。读者可以根据自己的需求查阅相关的文献 。
本文截选自《Go语言高级编程》
推荐阅读
- NTFS/exFAT/FAT32,这三个常见选项是什么意思?
- 汽车常见故障和快速解决办法
- 淘宝常见的促销手段 淘宝网店常见的促销策略有哪些
- 14项常见身体异常指标解读,千万别忽视
- 【微波炉维修】家用微波炉常见故障维修
- 大花蕙兰花语是什么
- 为什么微信听自己语音,会觉得难听不像自己声音?看完涨知识了
- 8种常见SQL错误用法,你中招了吗
- C语言中的顺序点
- Java的两种跳转语句