互斥锁()的互斥锁()
Lock()
return
defer
s.mu.Lock() defer s.mu.Unlock()
Unlock()
deferdeferdefer
同步。互斥体selectsync.Mutexdefault
下面是一个示例:它可能看起来像这样:
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")
}