Go语言多核并行化
并发和并行的概念
首先了解什么是并发什么是并行
Go当中实现多核多线程并发
注意:
注意区分什么是goroutine在并发和并行章节已经提到了.
获取当前操作系统CPU的核心数:
示例代码:
package main import ( "fmt" "runtime" ) /* 调用runtime包下的函数获取到当前操作系统的cpu核心数 */ func main() { cpuNum := runtime.NumCPU() fmt.Println("cpu核心数为:", cpuNum) /* 循环调用函数开启线程--->使用go关键字 */ for i := 0; i < 5; i++ { go func(index int) { sum := 0 for j := 0; j < 10000; j++ { sum += 1 } fmt.Printf("线程%d, sum值为:%d\n", index, sum) }(i) } }
注意:
在调用的时候不能直接使用传统的go run命令,需要使用go run -race命令才能看到goroutine当中的结果
模拟并行计算任务
计算 N 个整型数的总和。
将所有整型数分成 M 份,M 即 CPU 的个数。让每个 CPU 开始计算分给它的那份计算任务,最后将每个 CPU 的计算结果再做一次累加,
得到所有 N 个整型数的总和
示例代码:
package main import "runtime" type Vector []float64 // Op函数是一个公共累加函数 func (v Vector) Op(num float64) float64 { num = 1 return num } // 该类型实现的函数(执行运算函数) func (v Vector) DoSome(i, n int, u Vector, c chan int) { // 循环开启协程 for ; i < n ; i++ { v[i] += u.Op(v[i]) } // 将结果传输回到channel当中 c <- 1 } // 设置Cpu数量 var Ncpu = runtime.NumCPU() const NCPU = 8 // 这里注意常量和变量的区别,变量的声明和赋值不能够传递给常量 // 该类型分配的函数(分配cpu函数) func (v Vector) DoAll(u Vector) { // 声明任务完成的通道,该通道是个缓冲通道,缓冲通道 /* 这里注意make和new的区别 make:返回的是创建的对象本身 new:返回的是创建的对象的指针 */ c := make(chan int, NCPU) // 循环调用DoSome函数执行计算过程 for i := 0; i < NCPU; i++ { go v.DoSome(i*len(v)/NCPU, (i+1)*len(v)/NCPU, u, c) } // 等待所有cpu完成任务将数据放入缓冲通道 for i := 0; i < NCPU; i++ { <-c // 匿名接收 } }
注意:
实际上所有这些goroutine都运行在同一个CPU核心上,在一个goroutine得到时间片执行的时候,其他goroutine都会处于等待状态。