使用channel可实现协程同步,如通过无缓冲channel等待任务完成:main函数创建done通道,启动协程执行任务并发送完成信号,主线程接收信号后继续,确保任务结束前不退出。

在Golang中,协程(goroutine)之间的同步主要依赖于通道(channel)和标准库提供的同步原语。合理使用这些机制可以避免竞态条件、死锁等问题,确保多个协程协同工作时数据一致且执行有序。
Go提倡“通过通信共享内存”,而不是通过共享内存来通信。channel 是实现这一理念的核心工具。
无缓冲 channel 可用于两个协程间的同步点,比如等待某个任务完成:
示例:使用 channel 等待协程结束
func main() {
done := make(chan bool)
go func() {
fmt.Println("开始执行任务")
time.Sleep(1 * time.Second)
fmt.Println("任务完成")
done
}()
fmt.Println("等待任务完成...")
fmt.Println("主程序退出")
}
这里,主协程通过从 done 通道接收信号,实现对子协程的等待。
立即学习“go语言免费学习笔记(深入)”;
当需要等待多个协程完成时,sync.WaitGroup 更加方便。
它有三个方法:Add、Done、Wait。
示例:WaitGroup 控制多个协程同步
func main() {
var wg sync.WaitGroup
for i := 0; i
wg.Add(1)
go func(id int) {
defer wg.Done()
fmt.Printf("协程 %d 开始工作\n", id)
time.Sleep(time.Second)
fmt.Printf("协程 %d 完成\n", id)
}(i)
}
wg.Wait()
fmt.Println("所有协程已完成")
}
注意:Add 应在 goroutine 启动前调用,避免竞态;Done 通常用 defer 调用以确保执行。
当多个协程需要读写同一变量时,应使用互斥锁防止数据竞争。
示例:用 Mutex 保护计数器
func main() {
var mu sync.Mutex
var counter int
var wg sync.WaitGroup
for i := 0; i
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
counter++
mu.Unlock()
}()
}
wg.Wait()
fmt.Println("最终计数:", counter)
}
如果不加锁,counter++ 可能出现竞态,结果小于预期。
在实际应用中,常需限制协程执行时间。使用 context.WithTimeout 配合 channel 可安全中断操作。
示例:带超时的协程同步
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
ch := make(chan string)
go func() {
time.Sleep(3 * time.Second)
ch
}()
select {
case result :=
fmt.Println(result)
case
fmt.Println("任务超时")
}
}
这样即使协程未完成,也能在超时后继续执行,避免主程序卡住。
基本上就这些。根据场景选择合适的同步方式:简单通知用 channel,批量等待用 WaitGroup,共享变量加 Mutex,复杂控制结合 context。关键是避免死锁和竞态,保证程序健壮。
以上就是如何在Golang中实现协程间同步的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号