并发和并行的概念
首先了解
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