介绍:为了充分了利用多cpu的优势,在Golang程序中,设置运行的cpu数目。
func main() {//获取系统当前cpu的数量num := runtime.NumCPU()//这里根据需求来设置整个go程序去使用几个cpuruntime.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 mainimport ("fmt""time"
)var (m = make(map[int]int, 10)
)// test函数就是计算n的阶乘
func test(n int) {res := 1for 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 +0x0main.test()C:/Users/W10/GolandProjects/goroutine/channel.go:19 +0x70main.main.func1()C:/Users/W10/GolandProjects/goroutine/channel.go:25 +0x39Previous write at 0x00c00013e480 by goroutine 7:main.main()C:/Users/W10/GolandProjects/goroutine/channel.go:25 +0x84Goroutine 7 (finished) created at:main.main()C:/Users/W10/GolandProjects/goroutine/channel.go:25 +0x84Found 2 data race(s)
可以看到有几个数据发生竞争关系。
现在要解决这个问题有两个办法,一个就是使用全局变量加锁搞定。当任何协程去操作这个空间时候看看是否加锁,如果加锁了其他协程就需要等待。
不同goroutine之间如何通讯
1)全局变量加锁同步
2)channel
使用全局变量加锁同步改进程序
>因为没有对全局变量m加锁,因此会出现资源争夺问题,代码会出现错误,提示concurrent map writes
>解决方案:加入互斥锁
>我们的数的阶乘很大,结果会越界,可以将求阶乘改成sum+=uint64(i)
package mainimport ("fmt""sync""time"
)var (m = make(map[int]int, 10)//声明一个全局的互斥锁 lock是一个全局的互斥锁//sync是包 同步的意思 mutex是互斥的意思lock sync.Mutex
)// test函数就是计算n的阶乘
func test(n int) {res := 1for i := 1; i <= n; i++ {res = res * i}//将计算结果放到map当中 加锁lock.Lock()m[n] = reslock.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)}
}