Dictionary 使用sync.Map确保只有一个goroutine正在运行

Dictionary 使用sync.Map确保只有一个goroutine正在运行,dictionary,go,concurrency,synchronization,locking,Dictionary,Go,Concurrency,Synchronization,Locking,我有一个HTTP处理程序,它从查询接收一个参数。我不想为同一查询参数同时运行此处理程序,即在一个时间点上只应运行一个goroutine 这是我的想法: import "sync" import "fmt" var safeMap = sync.Map{} func handler(c) { _, loaded := safeMap.LoadOrStore(c.param, 1) // loaded is true if value was loaded and false if s

我有一个HTTP处理程序,它从查询接收一个参数。我不想为同一查询参数同时运行此处理程序,即在一个时间点上只应运行一个goroutine

这是我的想法:

import "sync"
import "fmt"

var safeMap = sync.Map{}

func handler(c) {

    _, loaded := safeMap.LoadOrStore(c.param, 1) // loaded is true if value was loaded and false if stored 
    fmt.Println(loaded)

    if loaded {
        c.JSON(http.StatusLocked, "locked")
        return
    }

    go doWork(c.param)

    safeMap.Delete(c.param)

    c.JSON(http.StatusOK, "done")
}

但是,无论何时发送两个已加载的并发请求,这两个请求都为false,并且这两个请求都会得到处理。为什么?

问题是你在一个新的工作环境中工作。如果param尚未锁定,则处理程序将其锁定,并启动一个goroutine来执行该工作。但是服务于请求的goroutine不会等待工作完成,它会立即解锁param

相反,在处理程序中执行该工作,因此只有在doWork返回时才会解锁参数:


您正在启动一个goroutine来完成工作,然后在工作有机会完成之前立即删除密钥。因此,锁争用的可能性非常小


为什么要使用go doWork而不是doWork?

因为doWork需要很长时间,我不希望请求等待。这更像是一个异步任务。然后,您还需要将锁管理移到该goroutine中。
doWork(c.param) // Note no 'go' keyword