[英]GoLang sequential goroutines
我是 golang 的新手,并且有一个用例,其中对类型的值的操作必须以顺序方式运行,而对其他类型的值的操作可以同时运行。
key_name_1, value_1 key_name_2, value_2 key_name_1, value_1
key_name_1
和key_name_2
可以由 goroutine 并发操作。key_name_1
,所以如果前面的操作(第 1 行)已经完成,这个操作应该只由 goroutine 处理,否则它应该等待第一个操作完成才能应用操作。 为了便于讨论,我们可以假设操作只是将新值添加到先前值。在golang中以最高性能实现这一目标的正确方法是什么?
确切的用例是数据库更改在队列上进行流式传输,现在如果一个值发生更改,重要的是在另一个数据库上对该操作应用相同的序列,否则一致性将受到影响。 冲突很少见,但可能会发生。
作为给定密钥的互斥性的简单解决方案,您可以只使用一个锁定的 map 的引用计数锁。 它不是高负载的最佳选择,但在您的情况下可能就足够了。
type processLock struct {
mtx sync.Mutex
refcount int
}
type locker struct {
mtx sync.Mutex
locks map[string]*processLock
}
func (l *locker) acquire(key string) {
l.mtx.Lock()
lk, found := l.locks[key]
if !found {
lk = &processLock{}
l.locks[key] = lk
}
lk.refcount++
l.mtx.Unlock()
lk.mtx.Lock()
}
func (l *locker) release(key string) {
l.mtx.Lock()
lk := l.locks[key]
lk.refcount--
if lk.refcount == 0 {
delete(l.locks, key)
}
l.mtx.Unlock()
lk.mtx.Unlock()
}
只需在处理密钥之前调用acquire(key)
,完成后调用release(key)
。
现场演示。
警告,上面的代码保证排他性。 但不是序列。 要按顺序解锁,您需要一个FIFO mutex 。
只是关于具有固定数量的工人的消息路由的建议。
IDK 如果它是最快的,我猜不是,但它很简单且可重新配置(通过一些努力可以使其 JiT 可调整大小)。
我确实相信散列部分可以优化,并且存在一些聪明的技术。 否则,您还可以通过增加通道缓冲区来堆积 memory 中的一些项目,再次简单。
无论如何, https://go.dev/play/p/fnxNJ9VZK8q
// You can edit this code!
// Click here and start typing.
package main
import (
"fmt"
"hash/fnv"
"sync"
)
func main() {
events := []map[string]interface{}{
map[string]interface{}{
"key1": "v",
"key2": "v",
"key3": "v",
},
map[string]interface{}{
"key1": "v",
"key2": "v",
"key3": "v",
},
}
type workerWork struct {
work interface{}
workerID int
}
workers := 4
inputs := []chan interface{}{}
output := make(chan workerWork)
var wg sync.WaitGroup
for i := 0; i < workers; i++ {
i := i
input := make(chan interface{})
inputs = append(inputs, input)
wg.Add(1)
go func() {
defer wg.Done()
for v := range input {
output <- workerWork{work: v, workerID: i}
}
}()
}
go func() {
wg.Wait()
close(output)
}()
go func() {
h := fnv.New32a()
for _, batch := range events {
for k, v := range batch {
h.Write([]byte(k))
ui := int(h.Sum32())
d := ui % workers
inputs[d] <- map[string]interface{}{k: v}
h.Reset()
}
}
for _, i := range inputs {
close(i)
}
}()
for work := range output {
fmt.Printf("%#v\n", work)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.