1 回答

TA貢獻1895條經驗 獲得超7個贊
當互斥體被鎖定時,對互斥鎖()的
所有其他調用都將被阻止,直到首先調用互斥鎖()
為止。
因此,當處理程序正在運行(并持有互斥鎖)時,所有其他請求將在調用時被阻止。Lock()
注意:如果您的處理程序由于您提前返回(使用語句)而無法正常完成,或者它崩潰了,您的互斥鎖將保持鎖定狀態,因此所有進一步的請求都將被阻止。return
一個好的做法是在互斥體被鎖定后立即使用 defer
來解鎖它:
s.mu.Lock() defer s.mu.Unlock()
這確保了無論您的函數如何結束(可能正常結束,返回或恐慌),都將被調用。Unlock()
嘗試盡可能少地保持鎖定,以最大程度地減少其他請求的阻塞時間。雖然在進入處理程序時正確鎖定并在返回之前僅解鎖可能很方便,但如果在處理程序的“生存期”內不使用受保護的資源,則僅在使用共享資源時才鎖定和解鎖。例如,如果要保護對文件的并發訪問,請鎖定互斥鎖,讀/寫文件,并在完成后立即解鎖互斥鎖。如何處理讀取數據以及如何組裝和發送響應不應阻止其他請求。當然,在使用解鎖時,它可能不會像它應該的那樣早運行(當您完成共享資源時)。因此,在某些情況下,可以使用 不使用 ,或者訪問共享資源的代碼可能會被移動到命名或未命名(匿名)函數,以便仍然能夠使用 。defer
defer
defer
同步?;コ怏w
不支持“掃視”狀態,也不支持“嘗試鎖定”操作。這意味著使用時,您無法向客戶端發出它必須等待的信號,因為處理請求正在等待另一個請求完成。如果您需要此類功能,則可以使用通道。容量為 1 的緩沖通道可以實現此功能:“鎖定”操作在通道上發送值,“解鎖”操作從通道接收值。目前為止,一切都好?!皌ry-lock”操作可以是“有條件的”發送操作:使用帶有事例的 select
語句,您可以檢測到您現在無法鎖定,因為它已被鎖定,您可以執行其他操作或同時執行其他操作,并在以后重試鎖定。sync.Mutex
default
下面是一個示例:它可能看起來像這樣:
var lock = make(chan struct{}, 1)
func handler(w http.ResponseWriter, r *http.Request) {
// Try locking:
select {
case lock <- struct{}{}:
// Success: proceed
defer func() { <-lock }() // Unlock deferred
default:
// Another handler would block us, send back an "error"
http.Error(w, "Try again later", http.StatusTooManyRequests)
return
}
time.Sleep(time.Second * 2) // Simulate long computation
io.WriteString(w, "Done")
}
func main() {
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
上面的簡單示例如果另一個請求持有鎖定,則會立即返回錯誤。你可以選擇在這里做不同的事情:你可以把它放在一個循環中,在放棄并返回錯誤之前重試幾次(在迭代之間稍微睡覺)。您可以在嘗試鎖定時使用超時,并且只有在一段時間內無法獲得鎖定時才接受“失敗”(請參閱時間。After() 和上下文。WithTimeout())。當然,如果我們使用某種超時,則必須刪除該案例(如果其他案例都不能立即進行,則立即選擇該案例)。defaultdefault
當我們處于它(超時)時,由于我們已經在使用 ,因此我們可以合并監視請求的上下文是一個好處:如果它被取消,我們應該提前終止并返回。為此,我們可以通過添加從上下文的 done 通道接收的案例來執行此操作,例如 。selectcase <-r.Context().Done():
下面是一個示例,如何簡單地使用:select
var lock = make(chan struct{}, 1)
func handler(w http.ResponseWriter, r *http.Request) {
// Wait 1 sec at most:
ctx, cancel := context.WithTimeout(r.Context(), time.Second)
defer cancel()
// Try locking:
select {
case lock <- struct{}{}:
// Success: proceed
defer func() { <-lock }() // Unlock deferred
case <-ctx.Done():
// Timeout or context cancelled
http.Error(w, "Try again later", http.StatusTooManyRequests)
return
}
time.Sleep(time.Second * 2) // Simulate long computation
io.WriteString(w, "Done")
}
- 1 回答
- 0 關注
- 118 瀏覽
添加回答
舉報