介绍:为了充分了利用多cpu的优势,在Golang程序中,设置运行的cpu数目。
func main() {
//获取系统当前cpu的数量
num := runtime.NumCPU()
//这里根据需求来设置整个go程序去使用几个cpu
runtime.GOMAXPROCS(num)
fmt.Println("num =", num)
}
比如你有逻辑的4个cpu,但是在程序里面只想使用3个。另外一个我要保留下来给其他程序使用,因为你占满了cpu导致其他程序可能跑不起来了。
(1)go1.8后,默认让程序运行在多个核上,可以不用设置了
(2)go1.8前,还是要设置一下,可以更高效的利益cpu
channel(管道)-看个需求
需求:现在要计算1-200的各个数的阶乘,并且把各个数的阶乘放入到map中。最后显示出来。要求使用goroutine完成
分析思路:
1)使用goroutine来完成,效率高,但是会出现并发/并行安全问题.
2)这里就提出了不同goroutine如何通信的问题
代码实现
1)使用goroutine来完成(看看使用gorotine并发完成会出现什么问题?然后我们会去解决)
2)在运行某个程序时,如何知道是否存在资源竞争问题。方法很简单,在编译该程序时,增加一个参数-race即可[示意图]
package main
import (
"fmt"
"time"
)
var (
m = make(map[int]int, 10)
)
// test函数就是计算n的阶乘
func test(n int) {
res := 1
for i := 1; i <= n; i++ {
res = res * i
}
//将计算结果放到map当中
m[n] = res
}
func main() {
//这里开启多协程完成任务
for i := 1; i <= 100; i++ {
go test(i)
}
time.Sleep(time.Second * 10)
for k, v := range m {
fmt.Println(k, v)
}
}
fatal error: concurrent map writes
多个协程在同时操作同一块的map空间。
==================
WARNING: DATA RACE
Write at 0x00c00013e480 by goroutine 8:
runtime.mapassign_fast64()
D:/Go/src/runtime/map_fast64.go:93 +0x0
main.test()
C:/Users/W10/GolandProjects/goroutine/channel.go:19 +0x70
main.main.func1()
C:/Users/W10/GolandProjects/goroutine/channel.go:25 +0x39
Previous write at 0x00c00013e480 by goroutine 7:
main.main()
C:/Users/W10/GolandProjects/goroutine/channel.go:25 +0x84
Goroutine 7 (finished) created at:
main.main()
C:/Users/W10/GolandProjects/goroutine/channel.go:25 +0x84
Found 2 data race(s)
可以看到有几个数据发生竞争关系。
现在要解决这个问题有两个办法,一个就是使用全局变量加锁搞定。当任何协程去操作这个空间时候看看是否加锁,如果加锁了其他协程就需要等待。
不同goroutine之间如何通讯
1)全局变量加锁同步
2)channel
使用全局变量加锁同步改进程序
>因为没有对全局变量m加锁,因此会出现资源争夺问题,代码会出现错误,提示concurrent map writes
>解决方案:加入互斥锁
>我们的数的阶乘很大,结果会越界,可以将求阶乘改成sum+=uint64(i)
package main
import (
"fmt"
"sync"
"time"
)
var (
m = make(map[int]int, 10)
//声明一个全局的互斥锁 lock是一个全局的互斥锁
//sync是包 同步的意思 mutex是互斥的意思
lock sync.Mutex
)
// test函数就是计算n的阶乘
func test(n int) {
res := 1
for i := 1; i <= n; i++ {
res = res * i
}
//将计算结果放到map当中 加锁
lock.Lock()
m[n] = res
lock.Unlock()
}
func main() {
//这里开启多协程完成任务
for i := 1; i <= 20; i++ {
go test(i)
}
time.Sleep(time.Second * 10)
for k, v := range m {
fmt.Println(k, v)
}
}