代码实现(以Go语言为例)
package main
import (
"fmt"
"sync"
)
func worker(id int, ch chan int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 5; i++ {
ch <- id*10 + i
}
}
func main() {
var wg sync.WaitGroup
ch := make(chan int)
numWorkers := 3
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go worker(i, ch, &wg)
}
go func() {
wg.Wait()
close(ch)
}()
for val := range ch {
fmt.Println(val)
}
}
可能出现的竞态条件及避免方法
- 竞态条件:
- 多个协程同时向Channel发送数据时,虽然Go语言的Channel本身是线程安全的,但是在关闭Channel时可能出现竞态条件。如果主协程在所有工作协程还未完成发送数据时就关闭了Channel,那么还未发送的数据将会丢失。
- 避免方法:
- 使用
sync.WaitGroup
。在每个工作协程开始时调用wg.Add(1)
,在工作协程结束时调用wg.Done()
。主协程通过wg.Wait()
等待所有工作协程完成后再关闭Channel,这样可以确保所有数据都被发送到Channel中。