作者 | zvalhu
Golang基于多线程、协程实现,与生俱来适合异步编程,当我们遇到那种需要批量处理且耗时的操作时,传统的线性执行就显得吃力,这时就会想到异步并行处理。下面介绍一些异步编程方式和技巧。
一、使用方式
1.最简单的最常用的方式:使用go关键词
或者:
使用匿名函数传递参数
这种方式不需要考虑返回值问题,如果要考虑返回值,可以使用下面的方式。
2.通过goroutine和channel来实现
3.使用sync.WaitGroup
sync.WaitGroup用于等待一组协程完成其任务。通过Add()方法增加等待的协程数量,Done()方法标记协程完成,Wait()方法阻塞直到所有协程完成。
4.使用errgroup实现协程组的错误处理
如果想简单获取协程返回的错误,errgroup包很适合,errgroup包是Go语言标准库中的一个实用工具,用于管理一组协程并处理它们的错误。可以使用errgroup.Group结构来跟踪和处理协程组的错误。
二、一些使用技巧
1.使用channel的range和close操作
range操作可以在接收通道上迭代值,直到通道关闭。可以使用close函数关闭通道,以向接收方指示没有更多的值。
2.使用select语句实现多个异步操作的等待
3.使用select和time.After()实现超时控制
如果需要在异步操作中设置超时,可以使用select语句结合time.After()函数实现。
4.使用select和time.After()实现超时控制
如果需要在异步操作中设置超时,可以使用select语句结合time.After()函数实现。
5.使用time.Tick()和time.After()进行定时操作
time.Tick()函数返回一个通道,定期发送时间值,可以用于执行定时操作。time.After()函数返回一个通道,在指定的时间后发送一个时间值。
6.使用sync.Mutex或sync.RWMutex进行并发安全访问
当多个协程并发访问共享数据时,需要确保数据访问的安全性。sync.Mutex和sync.RWMutex提供了互斥锁和读写锁,用于在访问共享资源之前进行锁定,以避免数据竞争。sync.RWMutex是一种读写锁,可以在多个协程之间提供对共享资源的并发访问控制。多个协程可以同时获取读锁,但只有一个协程可以获取写锁。
注意:sync.Mutex 的锁是不可以嵌套使用的 sync.RWMutex 的 RLock()是可以嵌套使用的 sync.RWMutex 的 mu.Lock() 是不可以嵌套的 sync.RWMutex 的 mu.Lock() 中不可以嵌套 mu.RLock()
7.使用sync.Cond进行条件变量控制
sync.Cond是一个条件变量,用于在协程之间进行通信和同步。它可以在指定的条件满足之前阻塞等待,并在条件满足时唤醒等待的协程。
8.使用sync.Pool管理对象池
sync.Pool是一个对象池,用于缓存和复用临时对象,可以提高对象的分配和回收效率。
9.使用sync.Once实现只执行一次的操作
sync.Once用于确保某个操作只执行一次,无论有多少个协程尝试执行它,常用于初始化或加载资源等场景。
10.使用sync.Once和context.Context实现资源清理
可以结合使用sync.Once和context.Context来确保在多个协程之间只执行一次资源清理操作,并在取消或超时时进行清理。
11.使用sync.Map实现并发安全的映射
sync.Map是Go语言标准库中提供的并发安全的映射类型,可在多个协程之间安全地进行读写操作。
12.使用context.Context进行协程管理和取消
context.Context用于在协程之间传递上下文信息,并可用于取消或超时控制。可以使用context.WithCancel()创建一个可取消的上下文,并使用context.WithTimeout()创建一个带有超时的上下文。
13.使用context.WithDeadline()和context.WithTimeout()设置截止时间
context.WithDeadline()和context.WithTimeout()函数可以用于创建带有截止时间的上下文,以限制异步任务的执行时间。
14.使用context.WithValue()传递上下文值
context.WithValue()函数可用于在上下文中传递键值对,以在协程之间共享和传递上下文相关的值。
15.使用atomic包进行原子操作
atomic包提供了一组函数,用于实现原子操作,以确保在并发环境中对共享变量的读写操作是原子的。