我有一个网络服务器,我想顺序执行一个 REST 调用,它会在网络服务器上创建一些文件。我试图防止客户端多次启动同一个文件的创建,因为它很昂贵。如果客户端尝试创建一个已经在进行中的文件,我想返回 HTTP 423。
我试着按照下面的结构从头开始写
type Procedure[ID comparable] func(ID)
type Sequentialization[ID comparable] struct {
Meta sync.Mutex
Locks map[ID]*sync.Mutex
Proc Procedure[ID]
}
但现在我想知道我是否是第一个需要这个的人。我在 Go 中有一种惯用的方法来做到这一点,我只是不知道?
这似乎有效。
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
type Procedure[ID comparable, ARG any] func(ID, ARG)
type Sequentialization[ID comparable, ARG any] struct {
MapMu sync.Mutex
SeqMu map[ID]*sync.Mutex
Proc Procedure[ID, ARG]
}
func NewSequentialization[ID comparable, ARG any](proc Procedure[ID, ARG]) (s *Sequentialization[ID, ARG]) {
s = new(Sequentialization[ID, ARG])
s.SeqMu = make(map[ID]*sync.Mutex)
s.Proc = proc
return
}
func (s *Sequentialization[ID, ARG]) Exec(id ID, arg ARG) {
// Create the sequentialization mutex
s.MapMu.Lock()
m, exists := s.SeqMu[id]
if !exists {
m = new(sync.Mutex)
s.SeqMu[id] = m
}
p := s.Proc
s.MapMu.Unlock()
// Sequentialize work
(*m).Lock()
p(id, arg)
(*m).Unlock()
// Delete the sequentialization mutex
s.MapMu.Lock()
delete(s.SeqMu, id)
s.MapMu.Unlock()
}
func say(id string, arg int) {
fmt.Print("[")
for i := 0; i < 5; i++ {
fmt.Print(arg)
time.Sleep(100 * time.Millisecond)
}
fmt.Println("]")
}
func main() {
s := NewSequentialization(say)
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
r := rand.Intn(90) + 10
fmt.Println(r)
wg.Add(1)
go func() {
defer wg.Done()
s.Exec("id", r)
}()
}
wg.Wait()
}