新聞中心
Go語言具有支持高并發(fā)的特性,可以很方便地實(shí)現(xiàn)多線程運(yùn)算,充分利用多核心 cpu 的性能。

成都創(chuàng)新互聯(lián)專注于圖木舒克企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站,商城網(wǎng)站開發(fā)。圖木舒克網(wǎng)站建設(shè)公司,為圖木舒克等地區(qū)提供建站服務(wù)。全流程按需搭建網(wǎng)站,專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,成都創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)
眾所周知服務(wù)器的處理器大都是單核頻率較低而核心數(shù)較多,對(duì)于支持高并發(fā)的程序語言,可以充分利用服務(wù)器的多核優(yōu)勢(shì),從而降低單核壓力,減少性能浪費(fèi)。
Go語言實(shí)現(xiàn)多核多線程并發(fā)運(yùn)行是非常方便的,下面舉個(gè)例子:
package main
import (
"fmt"
)
func main() {
for i := 0; i < 5; i++ {
go AsyncFunc(i)
}
}
func AsyncFunc(index int) {
sum := 0
for i := 0; i < 10000; i++ {
sum += 1
}
fmt.Printf("線程%d, sum為:%d\n", index, sum)
}運(yùn)行結(jié)果如下:
線程0, sum為:10000
線程2, sum為:10000
線程3, sum為:10000
線程1, sum為:10000
線程4, sum為:10000
在執(zhí)行一些昂貴的計(jì)算任務(wù)時(shí),我們希望能夠盡量利用現(xiàn)代服務(wù)器普遍具備的多核特性來盡量將任務(wù)并行化,從而達(dá)到降低總計(jì)算時(shí)間的目的。此時(shí)我們需要了解 CPU 核心的數(shù)量,并針對(duì)性地分解計(jì)算任務(wù)到多個(gè) goroutine 中去并行運(yùn)行。
下面我們來模擬一個(gè)完全可以并行的計(jì)算任務(wù):計(jì)算 N 個(gè)整型數(shù)的總和。我們可以將所有整型數(shù)分成 M 份,M 即 CPU 的個(gè)數(shù)。讓每個(gè) CPU 開始計(jì)算分給它的那份計(jì)算任務(wù),最后將每個(gè) CPU 的計(jì)算結(jié)果再做一次累加,這樣就可以得到所有 N 個(gè)整型數(shù)的總和:
type Vector []float64
// 分配給每個(gè)CPU的計(jì)算任務(wù)
func (v Vector) DoSome(i, n int, u Vector, c chan int) {
for ; i < n; i++ {
v[i] += u.Op(v[i])
}
c <- 1 // 發(fā)信號(hào)告訴任務(wù)管理者我已經(jīng)計(jì)算完成了
}
const NCPU = 16 // 假設(shè)總共有16核
func (v Vector) DoAll(u Vector) {
c := make(chan int, NCPU) // 用于接收每個(gè)CPU的任務(wù)完成信號(hào)
for i := 0; i < NCPU; i++ {
go v.DoSome(i*len(v)/NCPU, (i+1)*len(v)/NCPU, u, c)
}
// 等待所有CPU的任務(wù)完成
for i := 0; i < NCPU; i++ {
<-c // 獲取到一個(gè)數(shù)據(jù),表示一個(gè)CPU計(jì)算完成了
}
// 到這里表示所有計(jì)算已經(jīng)結(jié)束
}這兩個(gè)函數(shù)看起來設(shè)計(jì)非常合理,其中 DoAll() 會(huì)根據(jù) CPU 核心的數(shù)目對(duì)任務(wù)進(jìn)行分割,然后開辟多個(gè) goroutine 來并行執(zhí)行這些計(jì)算任務(wù)。
是否可以將總的計(jì)算時(shí)間降到接近原來的 1/N 呢?答案是不一定。如果掐秒表,會(huì)發(fā)現(xiàn)總的執(zhí)行時(shí)間沒有明顯縮短。再去觀察 CPU 運(yùn)行狀態(tài),你會(huì)發(fā)現(xiàn)盡管我們有 16 個(gè) CPU 核心,但在計(jì)算過程中其實(shí)只有一個(gè) CPU 核心處于繁忙狀態(tài),這是會(huì)讓很多Go語言初學(xué)者迷惑的問題。
官方給出的答案是,這是當(dāng)前版本的 Go 編譯器還不能很智能地去發(fā)現(xiàn)和利用多核的優(yōu)勢(shì)。雖然我們確實(shí)創(chuàng)建了多個(gè) goroutine,并且從運(yùn)行狀態(tài)看這些 goroutine 也都在并行運(yùn)行,但實(shí)際上所有這些 goroutine 都運(yùn)行在同一個(gè) CPU 核心上,在一個(gè) goroutine 得到時(shí)間片執(zhí)行的時(shí)候,其他 goroutine 都會(huì)處于等待狀態(tài)。從這一點(diǎn)可以看出,雖然 goroutine 簡(jiǎn)化了我們寫并行代碼的過程,但實(shí)際上整體運(yùn)行效率并不真正高于單線程程序。
雖然Go語言還不能很好的利用多核心的優(yōu)勢(shì),我們可以先通過設(shè)置環(huán)境變量 GOMAXPROCS 的值來控制使用多少個(gè) CPU 核心。具體操作方法是通過直接設(shè)置環(huán)境變量 GOMAXPROCS 的值,或者在代碼中啟動(dòng) goroutine 之前先調(diào)用以下這個(gè)語句以設(shè)置使用 16 個(gè) CPU 核心:
runtime.GOMAXPROCS(16)
到底應(yīng)該設(shè)置多少個(gè) CPU 核心呢,其實(shí) runtime 包中還提供了另外一個(gè) NumCPU() 函數(shù)來獲取核心數(shù),示例代碼如下:
package main
import (
"fmt"
"runtime"
)
func main() {
cpuNum := runtime.NumCPU() //獲得當(dāng)前設(shè)備的cpu核心數(shù)
fmt.Println("cpu核心數(shù):", cpuNum)
runtime.GOMAXPROCS(cpuNum) //設(shè)置需要用到的cpu數(shù)量
}運(yùn)行結(jié)果如下:
cpu核心數(shù): 4
網(wǎng)站題目:創(chuàng)新互聯(lián)GO教程:Go語言多核并行化
本文路徑:http://www.dlmjj.cn/article/dhccpid.html


咨詢
建站咨詢
