3 回答

TA貢獻1796條經驗 獲得超4個贊
關于Go的goroutine,有幾點需要牢記:
從Java或C ++線程的意義上來說,它們不是線程
goroutines更像是greenlet
go運行時在系統線程之間多路復用goroutines
系統線程的數量由環境變量控制,
GOMAXPROCS
我認為當前默認為1。將來可能會改變goroutine屈服于其當前線程的方式由幾種不同的結構控制
在select語句可以產生控制回線
在通道上發送可以將控制權交還給線程
進行IO操作可以將控制權交還給線程
runtime.Gosched()
顯式地將控制權交還給線程
您看到的行為是因為main函數從不屈服于線程,而是參與了繁忙的循環,并且因為只有一個線程,所以main循環無處運行。

TA貢獻1862條經驗 獲得超6個贊
根據這個和這個,幾個電話不能CPU密集型夠程的過程中調用(如果夠程從不屈服于調度)。如果其他Goroutine需要阻塞主線程,這可能會導致它們掛起(例如,所使用的write()syscall就是這種情況fmt.Println())
我發現的解決方案涉及到調用runtime.Gosched()與CPU綁定的線程,以將其返回給調度程序,如下所示:
package main
import (
"fmt"
"runtime"
)
var x = 1
func inc_x() {
for {
x += 1
runtime.Gosched()
}
}
func main() {
go inc_x()
for {
fmt.Println(x)
}
}
因為你只有在夠程執行一個操作,runtime.Gosched()是被稱為非常頻繁。調用runtime.GOMAXPROCS(2)init的速度快一個數量級,但是如果您做的事情比增加數字復雜得多(例如,處理數組,結構,映射等),則調用init會非常不安全。
在那種情況下,最佳實踐可能是使用渠道來管理對資源的共享訪問。

TA貢獻1865條經驗 獲得超7個贊
這是兩件事的相互作用。一個默認情況下,Go僅使用單個內核,第二個Go必須協同計劃goroutine。您的函數inc_x不會屈服,因此會壟斷所使用的單個內核。消除這些條件中的任何一個都將導致您期望的輸出。
說“核心”有點含糊。Go實際上可能在后臺使用了多個內核,但是它使用一個名為GOMAXPROCS的變量來確定線程數,以調度執行非系統任務的goroutine。如FAQ和Effective Go中所述,默認值為1,但可以使用環境變量或運行時函數將其設置為更高的值。這可能會提供您期望的輸出,但前提是您的處理器具有多個內核。
獨立于內核和GOMAXPROCS,您可以為運行時的goroutine調度程序提供完成其工作的機會。調度程序無法搶占正在運行的goroutine,而必須等待它返回運行時并請求某些服務,例如IO,time.Sleep()或runtime.Gosched()。在inc_x中添加類似的內容會產生預期的輸出。運行main()的goroutine已經通過fmt.Println請求服務,因此,由于這兩個goroutine現在定期屈服于運行時,因此它可以進行某種公平的調度。
- 3 回答
- 0 關注
- 261 瀏覽
添加回答
舉報