Go 通道值的互斥写锁定
我有一个包含数千个ID的通道,需要在goroutines中并行处理。如果在通道中重复,我如何实现一个锁,使goroutines不能同时处理相同的idGo 通道值的互斥写锁定,go,Go,我有一个包含数千个ID的通道,需要在goroutines中并行处理。如果在通道中重复,我如何实现一个锁,使goroutines不能同时处理相同的id package main import ( "fmt" "sync" "strconv" "time" ) var wg sync.WaitGroup func main() { var data []string for d := 0; d < 30; d++ { dat
package main
import (
"fmt"
"sync"
"strconv"
"time"
)
var wg sync.WaitGroup
func main() {
var data []string
for d := 0; d < 30; d++ {
data = append(data, "id1")
data = append(data, "id2")
data = append(data, "id3")
}
chanData := createChan(data)
for i := 0; i < 10; i++ {
wg.Add(1)
process(chanData, i)
}
wg.Wait()
}
func createChan(data []string) <-chan string {
var out = make(chan string)
go func() {
for _, val := range data {
out <- val
}
close(out)
}()
return out
}
func process(ids <-chan string, i int) {
go func() {
defer wg.Done()
for id := range ids {
fmt.Println(id + " (goroutine " + strconv.Itoa(i) + ")")
time.Sleep(1 * time.Second)
}
}()
}
-编辑:
所有值都需要按任意顺序处理,但id1、id2和id3需要阻塞,因此它们不能由多个goroutine同时处理。这里最简单的解决方案是根本不发送重复值,然后不需要同步
func createChan(data []string) <-chan string {
seen := make(map[string]bool)
var out = make(chan string)
go func() {
for _, val := range data {
if seen[val] {
continue
}
seen[val] = true
out <- val
}
close(out)
}()
return out
}
我找到了解决办法。有人编写了一个包github.com/EagleChen/mapmutex来完成我所需要的工作:
package main
import (
"fmt"
"github.com/EagleChen/mapmutex"
"strconv"
"sync"
"time"
)
var wg sync.WaitGroup
var mutex *mapmutex.Mutex
func main() {
mutex = mapmutex.NewMapMutex()
var data []string
for d := 0; d < 30; d++ {
data = append(data, "id1")
data = append(data, "id2")
data = append(data, "id3")
}
chanData := createChan(data)
for i := 0; i < 10; i++ {
wg.Add(1)
process(chanData, i)
}
wg.Wait()
}
func createChan(data []string) <-chan string {
var out = make(chan string)
go func() {
for _, val := range data {
out <- val
}
close(out)
}()
return out
}
func process(ids <-chan string, i int) {
go func() {
defer wg.Done()
for id := range ids {
if mutex.TryLock(id) {
fmt.Println(id + " (goroutine " + strconv.Itoa(i) + ")")
time.Sleep(1 * time.Second)
mutex.Unlock(id)
}
}
}()
}
根据定义,您所述的问题很难解决,我的第一选择是重新设计应用程序以避免它,但如果这不是一个选项: 首先,我假设如果一个给定的ID被重复,你仍然希望它被处理两次,但如果不是这样的话,那么第二个实例必须被忽略,这就变得更加困难,因为你必须永远记住你处理过的每个ID,所以你不需要对它运行两次任务 为了实现您的目标,您必须跟踪goroutine中正在执行的每个ID-go map是您在此处的最佳选择请注意,它的大小将增长到与您并行旋转的goroutine数量相同的大小!。映射本身必须受到锁的保护,因为它是从多个goroutine中修改的 我要做的另一个简化是,如果发现另一个gorotuine当前正在处理一个从通道中删除的ID,则可以将其添加回通道中。然后,我们需要map[string]bool作为跟踪设备,加上一个sync.Mutex来保护它。为简单起见,我假设map、mutex和channel是全局变量;但这可能对您不方便-安排访问您认为合适的goroutine、closure等参数
import "sync"
var idmap map[string]bool
var mtx sync.Mutex
var queue chan string
func process_one_id(id string) {
busy := false
mtx.Lock()
if idmap[id] {
busy = true
} else {
idmap[id] = true
}
mtx.Unlock()
if busy { // put the ID back on the queue and exit
queue <- id
return
}
// ensure the 'busy' mark is cleared at the end:
defer func() { mtx.Lock(); delete(idmap, id); mtx.Unlock() }()
// do your processing here
// ....
}
最简单的方法可能是创建一个全局映射[yourIDType]*sync.Mutex。为什么不在并发访问数据之前对其进行重复数据消除呢。无论如何,您都需要序列化访问,那么为什么可能会阻止所有相当于映射查找的内容呢?谢谢Adrian,我不相信您可以这样做,因为映射不是线程安全的,并且在并发访问时会出现恐慌。谢谢Jim,不幸的是,这是不可能的解决方案。该示例针对堆栈溢出进行了简化,但存在使用外键关系处理的数据。因此,目标是不同时写入该记录。