假设我们的 CPU
核数是 NCPU
个: const NCPU = 4
// 例如:4 代表 4 核处理器,我们将计算划分为 NCPU
部分,每部分与其他部分并行运行。
下面是一个简单的示例(我们忽略具体的参数):
func DoAll() {
sem := make(chan int, NCPU)
for i := 0; i < NCPU; i++ {
// Buffering optional but sensible. 合理的缓冲区选项(个人理解就是和 CPU 的核心数相同)
go DoPart(sem)
}
// 等待 NCPU 任务完成,释放通道 sem 的缓冲区
for i := 0; i < NCPU; i++ {
<-sem // 等待一个任务完成
}
// 全部完成。
}
func DoPart(sem chan int) {
// 进行计算的部分
...
sem <- 1 // 发送一个这部分已经完成的信号,用来释放 sem 的缓冲区
}
func main() {
runtime.GOMAXPROCS = NCPU
DoAll()
}
- 函数
DoAll()
生成一个通道 sem ,在此基础上完成每一个并行计算;在 for 循环中启动NCPU
个协程,每一个协程执行全部工作的1/NCPU
。通过 sem 发送每一个协程中DoPart()
完成的信号。 DoAll()
中用一个 for 循环来等待所有 (NCPU
个)协程完成计算: 通道 sem 的行为就像一个 semaphore(信号量) ;这个代码展示了一个典型的 信号量模式(可以参见 14.2.7 章节)
在当前的运行模式下,你还必须设置 GOMAXPROCS
为 NCPU
(可以参见 14.1.3)