go语言中使用WaitGroup和channel实现处理多线程问题

07-11 1792阅读

WaitGroup

背景

如果将一个任务分为任意个小任务,并且不关心小任务的执行顺序,并且希望等待全部的小任务执行完成后再去操作后面的逻辑,那我推荐你用sync.WaitGRoup

go语言中使用WaitGroup和channel实现处理多线程问题
(图片来源网络,侵删)

使用方法

比如,有一个任务需要执行 3 个子任务,那么可以这样写:

package main
import (
	"fmt"
	"sync"
)
func main() {
	// 定义信号量
	var wg sync.WaitGroup
	// wg 添加任务数量
	wg.Add(3)
	// 创建三个携程处理wg
	go func(i int, wg *sync.WaitGroup) {
		// 提前定义结束
		defer wg.Done()
		fmt.Printf("执行任务%d\n", i)
	}(1, &wg)
	go func(i int, wg *sync.WaitGroup) {
		// 提前定义结束
		defer wg.Done()
		fmt.Printf("执行任务 %d\n", i)
	}(2, &wg)
	go func(i int, wg *sync.WaitGroup) {
		// 提前定义结束
		defer wg.Done()
		fmt.Printf("执行任务 %d\n", i)
	}(3, &wg)
	// 等待所有携程执行完毕
	fmt.Println("等待所有任务执行中....")
	wg.Wait()
	fmt.Println("所有任务执行完了....")
}

踩坑点避免

1.调用时应该调用&wg而不是wg(调用引用)

// 正确
go handlerTask1(&wg)
// 错误
go handlerTask1(wg)

2.确保wg.Add()应该在wg.Wait()之前执行

 // 错误
var wg sync.WaitGroup
go handlerTask1(&wg)
wg.Wait()
...
func handlerTask1(wg *sync.WaitGroup) {
	wg.Add(1)
	defer wg.Done()
	fmt.Println("执行任务 1")
}

3.注意 wg.Add() 和 wg.Done() 的计数器保持一致

小结

sync.WaitGroup 使用起来比较简单,一定要注意不要踩到坑里。

其实 sync.WaitGroup 使用场景比较局限,仅适用于等待全部子任务执行完毕后,再进行下一步处理,如果需求是当第一个子任务执行失败时,通知其他子任务停止运行,这时 sync.WaitGroup 是无法满足的,需要使用到通知机制(channel)。

Channel

由于时间原因,在这里只简单讲一下Channel的作用吧

1.作为锁保证多协程执行时线程安全

2.控制并发数量

https://juejin.cn/post/7175028144812851237

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]