我的程序是這樣的:func handle(conn net.Conn) { msg := "hello, world!" for i:= 0; i< 100000; i++ { go func() { err := write(conn, msg) } }}func write(conn net.Conn, msg string) error { mlen := fmt.Sprintf("%04d", len(msg)) _, err := conn.Write([]byte(mlen + msg)) return err}該程序將同時運行 100000 個 goroutine,并且所有 goroutine 將向同一個連接發送消息。我懷疑服務器會收到類似“hellohelloworldworld”的錯誤消息,但是當程序在我的 Ubuntu 14.04LTS 中運行時沒有問題。那么,多個 goroutine 會同時調用 Conn 上的方法嗎?=========================================================================我怎樣才能保持Write方法的原子性?
2 回答

PIPIONE
TA貢獻1829條經驗 獲得超9個贊
該文檔指出:
多個 goroutine 可以同時調用 Conn 上的方法。
沒有提到每個單獨的寫入是否是原子的。雖然當前的實現可以確保每次調用都Write
在下一次調用開始之前完全發生,但語言規范中并不能保證。

ABOUTYOU
TA貢獻1812條經驗 獲得超5個贊
這個答案意味著寫入是原子的。
io.Write 接口的具體實現者需要在發生部分寫入時返回錯誤。net.Conn 在 unix 上通過獲取鎖并在循環中調用 write 來處理這個問題,直到整個緩沖區都被寫入。在 Windows 上,它調用 WSASend,它保證發送整個緩沖區,除非發生錯誤。但是文檔確實有這個警告:
對 WSASend 的調用順序也是緩沖區傳輸到傳輸層的順序。WSASend 不應該在同一個面向流的套接字上同時從不同的線程調用,因為一些 Winsock 提供者可能會將一個大的發送請求分成多個傳輸,這可能會導致來自同一個面向流的多個并發發送請求的意外數據交錯插座。
這意味著它不一定是原子的,除非 Go 獲得了一個互斥體——它確實做到了。
所以基本上它在實踐中是原子的??梢韵胂螅粋€實現可以將線程安全定義為不崩潰,并通過解鎖調用 write 周圍的互斥鎖(或在 Windows 上根本不獲取它)來允許交錯寫入。但這對我來說沒有意義,而且開發人員清楚地表明了相反的意圖。
- 2 回答
- 0 關注
- 177 瀏覽
添加回答
舉報
0/150
提交
取消