2 回答

TA貢獻1805條經驗 獲得超10個贊
這里有幾點值得注意:
goroutines 不是線程。沒有“goroutine 數量”,系統中的 goroutine 數量也沒有固定的上限。1 可以修改 Bakery 算法以處理動態創建的線程(使用列表或映射,如 Wikipedia 頁面上的 Java 示例),但對每個“線程”有一個唯一 ID 的強烈要求,這使得這不是一個一般而言,Go 的好主意。(您可以依次使用實現類似線程行為的包來解決這個問題,包括線程 ID。)
正如維基百科頁面所指出的:
Lamport 的面包店算法假設一個順序一致性內存模型。很少有(如果有的話)語言或多核處理器實現這樣的內存模型。因此,算法的正確實現通常需要插入柵欄來禁止重新排序。
這意味著您將需要使用該
sync/atomic
包,這違背了編寫自己的鎖定的目的。
有了這兩個巨大的警告,你可以調用runtime.Gosched()
你會調用 POSIX 樣式yield()
函數的地方,或者你可以使用一個通道來表示有人“離開了面包店”,因此輪到下一個用戶了。但是渠道本身會完成您需要的所有互斥。一個簡化的特定于 Go 的非 Lamport 面包店算法是微不足道的(但以下所有內容都未經測試):
var takeANumber chan int64
var currentlyServing int64
init() {
takeANumber = make(chan int64)
go giveNumbers()
}
// giveNumbers hands out ever-increasing ticket numbers
func giveNumbers() {
for int64 i := 0;; i++ {
takeANumber <- i
}
}
// WaitTurn gets a ticket, then waits until it is our turn. You can
// call this "Lock" if you like.
func WaitTurn() int64 {
ticket := <-takeANumber
for atomic.LoadInt64(¤tlyServing) < ticket {
runtime.Gosched()
}
return ticket
}
// ExitBakery relinquishes our ticket, allowing the next user to proceed.
func ExitBakery(ticket int64) {
atomic.StoreInt64(¤tlyServing, ticket + 1)
}
將其修改為使用兩個通道,以便該WaitTurn功能更有效,留作練習。(當然,除了作為練習之外,沒有理由一開始就使用這些代碼。)
1您可以設置運行時限制,但如果您調用任何阻塞系統調用,系統無論如何都會產生額外的 goroutine。阻塞的系統調用集以及何時調用它們取決于運行時,因此您無法對此進行真正的控制,至少在不編寫特定于平臺的代碼的情況下是無法控制的。

TA貢獻1993條經驗 獲得超6個贊
在當前版本中,goroutine 不是可搶占的。這意味著如果你有一個緊密循環的 goroutine,那么這個 goroutine 不會將它正在運行的線程讓給其他 goroutine。有時這可能意味著沒有其他 goroutine 將永遠運行。
不要像這樣忙著等待,而是使用一個頻道:
<-specialCondition // Do stuff
并在特殊情況發生時關閉它。
您也可以嘗試使用 a sync.Cond
,但您可以使用通道執行條件變量所做的所有事情。
- 2 回答
- 0 關注
- 181 瀏覽
添加回答
舉報