Go语言如何向broadcast函数传入的多个未关闭channel单次发消息
问题修复方案
原代码核心问题
broadcast函数入参waitTime类型为time.Duration,调用时直接传数值5会被识别为5纳秒,远小于实际发送需要的时间,超时逻辑会直接触发send函数判断channel是否关闭的逻辑错误:循环读取channel内容会直接丢弃已有数据,空channel还会导致永久阻塞- 没有对
sentNumber做并发安全的计数控制,多goroutine同时修改会出现竞态问题 broadcast没有等待发送goroutine执行完成就直接返回0,无法得到正确的发送计数- 发送消息没有超时机制,遇到阻塞的channel会永久卡住
修复后实现代码
package main import ( "fmt" "sync" "time" ) var ( sentNumber int mu sync.Mutex ) func broadcast(waitTime time.Duration, message string, ch ...chan string) int { start := time.Now() var wg sync.WaitGroup for _, channel := range ch { // 全局超时判断,超过等待时间直接终止后续发送任务 if time.Since(start) >= waitTime { break } wg.Add(1) go func(c chan string, remainTime time.Duration) { defer wg.Done() send(c, message, remainTime) }(channel, waitTime - time.Since(start)) } // 等待所有发送任务执行完成后再返回计数 wg.Wait() mu.Lock() defer mu.Unlock() return sentNumber } func send(channel chan string, message string, timeout time.Duration) { // 捕获向已关闭channel发送消息触发的panic,避免程序崩溃 defer func() { recover() }() select { case channel <- message: // 发送成功后原子性递增计数 mu.Lock() sentNumber++ mu.Unlock() case <-time.After(timeout): // 发送超时直接退出,不做额外处理 return } } func main() { a := make(chan string, 1) b := make(chan string, 1) // 明确指定时间单位为秒,符合5秒超时的预期 count := broadcast(5*time.Second, "secret message", a, b) fmt.Printf("成功发送消息数:%d\n", count) fmt.Println(<-a) fmt.Println(<-b) }
核心修改说明
- 修复超时参数的单位问题,调用
broadcast时明确指定5*time.Second实现5秒超时控制 - 改用
select+time.After实现带超时的非阻塞发送逻辑,避免永久阻塞问题 - 新增
defer recover()逻辑,捕获向已关闭channel发送消息触发的panic - 新增
sync.Mutex控制sentNumber的并发修改,保证计数准确 - 新增
sync.WaitGroup等待所有发送goroutine执行完成后再返回最终计数
内容的提问来源于stack exchange,提问作者Mohammad Asghari
相关产品推荐
相关产品推荐

