假设我们的 CPU 核数是 NCPU 个: const NCPU = 4 // 例如:4 代表 4 核处理器,我们将计算划分为 NCPU 部分,每部分与其他部分并行运行。

    下面是一个简单的示例(我们忽略具体的参数):

    1. func DoAll() {
    2. sem := make(chan int, NCPU)
    3. for i := 0; i < NCPU; i++ {
    4. // Buffering optional but sensible. 合理的缓冲区选项(个人理解就是和 CPU 的核心数相同)
    5. go DoPart(sem)
    6. }
    7. // 等待 NCPU 任务完成,释放通道 sem 的缓冲区
    8. for i := 0; i < NCPU; i++ {
    9. <-sem // 等待一个任务完成
    10. }
    11. // 全部完成。
    12. }
    13. func DoPart(sem chan int) {
    14. // 进行计算的部分
    15. ...
    16. sem <- 1 // 发送一个这部分已经完成的信号,用来释放 sem 的缓冲区
    17. }
    18. func main() {
    19. runtime.GOMAXPROCS = NCPU
    20. DoAll()
    21. }
    • 函数 DoAll() 生成一个通道 sem ,在此基础上完成每一个并行计算;在 for 循环中启动 NCPU 个协程,每一个协程执行全部工作的 1/NCPU 。通过 sem 发送每一个协程中 DoPart() 完成的信号。
    • DoAll() 中用一个 for 循环来等待所有 (NCPU 个)协程完成计算: 通道 sem 的行为就像一个 semaphore(信号量) ;这个代码展示了一个典型的 信号量模式(可以参见 14.2.7 章节

    在当前的运行模式下,你还必须设置 GOMAXPROCSNCPU(可以参见 14.1.3