我有一个场景,我创建一个有4个工人的工作池。这些工作人员从通道中获取作业并将结果存储到内存中。 因此工作人员执行作业并可以并行更新结果。我想知道哪种数据类型最好保存结果,因为一次可以由多个工作人员访问。我需要使用锁机制来实现这一目标。
结果将是键值格式。因此,在这种情况下可以考虑地图。
答案 0 :(得分:2)
我会使用工作人员发送结果的第二个频道。一个goroutine将从此频道收到结果并存储它们。如果使用此方法,则不需要共享内存和受保护的代码部分。
编辑:示例
以下程序使用四个工作人员和一个结果收集器。任务从主要的gorouting传递给工人。工作人员将结果和错误发送给构建摘要的收集器。
package main
import (
"fmt"
"sync"
)
func main() {
tasks := make(chan int)
results := make(chan string)
var wg sync.WaitGroup
for i := 0; i < 4; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for task := range tasks {
rem := int(task) % 2
switch rem {
case 0:
results <- fmt.Sprintf("done with task %d", task)
case 1:
results <- fmt.Sprintf("error: only even tasks accepted: %d", task)
}
}
}()
}
summary := ""
go func() {
for result := range results {
summary += result + "\n"
}
}()
for i := 0; i < 10; i++ {
tasks <- i
}
close(tasks)
wg.Wait()
close(results)
fmt.Println(summary)
}
答案 1 :(得分:1)
是的,你可以使用地图,你必须用互斥锁来保护它。
但我建议每个作业都包含一个结果通道,您可以在其中输入作业的结果。这是一个粗略的草图,看起来像是什么:
playground:请注意,游乐场只有一个核心,所以数字会按顺序出现。
package main
import (
"fmt"
"time"
)
type job struct {
a int
b int
chRes chan int
}
func main() {
var chIn = make(chan job, 20)
for i := 0; i < 10; i++ {
go worker(chIn)
}
for i := 0; i < 100; i++ {
go func(i int) {
chRes := make(chan int)
chIn <- job{
a: i,
b: i,
chRes: chRes,
}
fmt.Println(<-chRes)
}(i)
}
// I'm lazy, so here just a sleep so we can see something
time.Sleep(1 * time.Second)
}
func worker(ch chan job) {
for job := range ch {
job.chRes <- job.a + job.b
}
}
- 编辑 -
如果你设备改为使用商店(哪种方式违背了咒语share memory by communicating
而不是communicate by sharing memory
):还有一个sync.Map
已经是并发安全的。不需要互斥。