互斥锁()的互斥锁()
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")

}