Go中用于并发读/写操作的数据类型

时间:2018-03-17 17:33:13

标签: multithreading go concurrency locking

我有一个场景,我创建一个有4个工人的工作池。这些工作人员从通道中获取作业并将结果存储到内存中。 因此工作人员执行作业并可以并行更新结果。我想知道哪种数据类型最好保存结果,因为一次可以由多个工作人员访问。我需要使用锁机制来实现这一目标。

结果将是键值格式。因此,在这种情况下可以考虑地图。

2 个答案:

答案 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)
}

请参阅https://play.golang.org/p/puZONnJHme-

答案 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已经是并发安全的。不需要互斥。