代码之家  ›  专栏  ›  技术社区  ›  tooptoop4

Golang-每值锁定

go
  •  1
  • tooptoop4  · 技术社区  · 4 年前

    我正在编写一个接受tableName值和updEpoch值的golang api,即:

    curl -F "tableName=abc" -F "updEpoch=123" myhost:8080/singleroute
    curl -F "tableName=abc" -F "updEpoch=456" myhost:8080/singleroute
    curl -F "tableName=def" -F "updEpoch=123" myhost:8080/singleroute
    curl -F "tableName=def" -F "updEpoch=345" myhost:8080/singleroute
    

    我想允许并行处理多个不同的tableName请求,但每个tableName只能同时处理一个请求。所以在上面的例子中,如果上述4个请求同时被触发,那么1st和3rd应该能够同时运行(作为唯一的表名),但是2nd只在1st完成时启动,4th只在3rd完成时启动。当我研究互斥时,似乎没有一个例子适合这种情况,我不想硬编码abc/定义等代码中的任何地方都应该使用相同的规则来处理任意的表名。

    根据克罗曼的帮助我猜:

    package main
    
    import (
        "fmt"
        "sync"
        "time"
        "http"
    )
    km := KeyedMutex{}
    type KeyedMutex struct {
        mutexes sync.Map // Zero value is empty and ready for use
    }
    
    func (m *KeyedMutex) Lock(key string) func() {
        value, _ := m.mutexes.LoadOrStore(key, &sync.Mutex{})
        mtx := value.(*sync.Mutex)
        mtx.Lock()
    
        return func() { mtx.Unlock() }
    }
    
    func myFunc(key string, data string) string {
      //do some stuff
      return "done for key:"+key+", data: "+data
    }
    
    func main() {
        key := //some form value sent to my api 
        data := //some form value sent to my api 
        unlock := km.Lock(key)
        defer unlock()
        retVal := myFunc(key, data)
    }
    
    1 回复  |  直到 4 年前
        1
  •  5
  •   Crowman    4 年前

    你可以使用 sync.Map *sync.Mutex 作为值。

    例如:

    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    type KeyedMutex struct {
        mutexes sync.Map // Zero value is empty and ready for use
    }
    
    func (m *KeyedMutex) Lock(key string) func() {
        value, _ := m.mutexes.LoadOrStore(key, &sync.Mutex{})
        mtx := value.(*sync.Mutex)
        mtx.Lock()
    
        return func() { mtx.Unlock() }
    }
    
    func main() {
        wg := sync.WaitGroup{}
        km := KeyedMutex{}
    
        for _, job := range []struct {
            key  string
            data string
        }{
            {key: "abc", data: "123"},
            {key: "abc", data: "456"},
            {key: "def", data: "123"},
            {key: "def", data: "456"},
        } {
            var job = job
            wg.Add(1)
    
            go func() {
                defer wg.Done()
    
                unlock := km.Lock(job.key)
                defer unlock()
    
                fmt.Printf("%s:%s mutex acquired\n", job.key, job.data)
                time.Sleep(time.Second * 1) // To ensure some goroutines visibly block
                fmt.Printf("%s:%s done\n", job.key, job.data)
            }()
        }
    
        wg.Wait()
    }
    

    带样本输出:

    crow@mac:$ ./mut
    def:456 mutex acquired
    abc:456 mutex acquired
    abc:456 done
    def:456 done
    abc:123 mutex acquired
    def:123 mutex acquired
    def:123 done
    abc:123 done
    crow@mac:$
    

    显示具有不同表名的请求立即获取互斥,但具有相同表名的请求被序列化。

        2
  •  1
  •   Alexander Trakhimenok    4 年前