這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
首先我們需要明確一下並行跟並發的區別,並發一般是被核心通過時間片或者中斷來控制的,遇到io阻塞或者時間片用完的時會轉移線程的使用權。一個核的情況下不可能有並行的情況,因為同一時間只有一個任務在調度。
該文章寫的有些亂,歡迎來噴 ! 另外文章後續不斷更新中,請到原文地址查看更新。
http://xiaorui.cc/2016/03/05/golang-runtime%E5%AE%9E%E7%8E%B0%E5%A4%9A%E6%A0%B8%E5%B9%B6%E8%A1%8C%E4%BB%BB%E5%8A%A1/
Golang預設所有的任務都在一個cpu核裡,如果想使用多核來跑goroutine的任務,需要配置runtime.GOMAXPROCS。 GOMAXPROCS的數目根據自己任務量分配就可以了,有個前提是不要大於你的cpu核心數。 並行比較適合那種cpu密集型計算,如果是IO密集型使用多核的化會增加cpu切換的成本。
Pythonpackage main//xiaorui.ccimport ("fmt""runtime")func test(c chan bool, n int) {x := 0for i := 0; i < 1000000000; i++ {x += i}println(n, x)if n == 10 {c <- true}}func main() {runtime.GOMAXPROCS(3)c := make(chan bool)for i := 0; i < 200; i++ {go test(c, i)}<-cfmt.Println("main end...")}
| 12345678910111213141516171819202122232425262728293031323334 |
package main//xiaorui.cc import ("fmt""runtime") func test(c chan bool, n int) { x := 0for i := 0; i < 1000000000; i++ {x += i}println(n, x)if n == 10 {c <- true}} func main() {runtime.GOMAXPROCS(3)c := make(chan bool) for i := 0; i < 200; i++ {go test(c, i)} <-c fmt.Println("main end...") } |
對於經常使用python multiprocessing多進程模組來跑多核多任務的我來說,不再有GIL全域鎖是個很美妙的事情。 我們通過top可以看到上面的執行個體代碼跑到了cpu 270% . 跟我們上面配置的runtime.GOMAXPROCS(3)相對應。
對於goroutine任務的終止也是有技巧的,他不能像多進程那樣,直接給kill掉。 他只能是通過類似flag訊號控制,每個goroutine執行的函數邏輯裡都要判斷flag標示位是否為stop狀態。
需要特意說明一點是,你在測試並發的時候,往往會把一個函數寫成死迴圈並做計算,你雖然這段函數用go關鍵詞並發了,但是你會發現他無法執行後面的邏輯。你需要做的是配置多核,或者是time.Sleep()。 這是為什麼 ? Golang是自己管理調整goroutine,如果你的一個func始終不釋放資源,那麼其他的goroutine不會去搶奪資源。 當然這樣的情境只有在測試時候遇到,正常情境下不可能沒有中斷和堵塞的情況。
Pythonpackage mainimport ("fmt""runtime"_ "time")var (flag = falsestr string)func xiaorui() {flag = truestr = "setup flag to true"}func main() {runtime.GOMAXPROCS(1)go xiaorui()//time.Sleep(1 * time.Second) // 理論來說,當我在xiaorui()把flag 改為true後,後面的邏輯會退出. for {if flag {break}}fmt.Println(str)}
| 12345678910111213141516171819202122232425262728293031 |
package main import ("fmt""runtime"_ "time") var (flag = falsestr string) func xiaorui() {flag = truestr = "setup flag to true"} func main() {runtime.GOMAXPROCS(1)go xiaorui()//time.Sleep(1 * time.Second) // 理論來說,當我在xiaorui()把flag 改為true後,後面的邏輯會退出. for {if flag {break}}fmt.Println(str)} |
我們不斷的調整的runtime.GOMAXPROCS(num) ,會發現執行的速度越來越快,但不要超過你的cpu數,因為那是徒勞的。 同樣的代碼我用python multiprocessing pool也實現了一份,我在MAC和線上伺服器做過測試,效能要遠高於python。