2 回答

TA貢獻1820條經驗 獲得超3個贊
Go 1.14 版本引入了異步搶占:
Goroutines 現在是異步可搶占的。因此,沒有函數調用的循環不再可能使調度程序死鎖或顯著延遲垃圾收集。
windows/arm
除、darwin/arm
、js/wasm
和之外的所有平臺都支持此功能plan9/*
。
正如在通道是否為 goroutine 調度發送搶占點中所回答的那樣?, Go 的搶占點可能會從一個版本到下一個版本發生變化。異步搶占幾乎在任何地方都增加了可能的搶占點。
您對數組的寫入output
未同步,并且您的oi
索引不是原子的,這意味著我們無法確定輸出數組會發生什么。當然,使用互斥體為其添加原子性會引入協作調度點。雖然這些不是協作調度切換的來源(必須根據您的輸出發生),但它們確實擾亂了我們對程序的理解。
數組保存了output
字符串,使用字符串可以調用垃圾回收系統,垃圾回收系統可以使用鎖,導致調度切換。因此,這是在 Go-1.14 之前的實現中調度切換的最可能原因。

TA貢獻1786條經驗 獲得超13個贊
正如@torek 所指出的那樣,最流行的 GO 運行時環境已經使用搶占式調度幾個月了(從 1.14 開始)。否則,goroutine 可能產生的點取決于運行時環境和版本,但威廉肯尼迪給出了一個很好的總結。
我還記得幾年前在編譯器中添加了一個選項來為長時間運行的循環添加屈服點,但這是一個通常不會觸發的實驗性選項。(當然,您可以通過runtime.GoSched
在循環中不時調用來手動執行此操作。)
至于你的測試,我對你在 Go 1.13.5 下運行時得到的結果感到驚訝。由于數據競爭,該行為并未完全定義(我知道您避免了任何同步機制以避免觸發產量),但我沒想到會出現這種結果。一件事是設置GOMAXPROCS
為 1 意味著只有一個 goroutine 正在并發執行,但這不一定意味著當不同的 goroutine 執行時它將在同一個核心上運行。不同的核心將具有不同的緩存和(沒有同步)對 和 的值的不同output
意見oi
。
但是我可以建議你忘記修改全局變量,只在忙循環之前和之后記錄一條消息。這應該清楚地表明(在 GO < 1.14 中)一次只能運行一個 lopp。(多年前我曾嘗試和你做同樣的實驗,這似乎奏效了。)
- 2 回答
- 0 關注
- 232 瀏覽
添加回答
舉報