是否map()和reduce()适合Go中的并发处理?

时间:2013-05-18 21:53:51

标签: concurrency functional-programming mapreduce go

来自python背景,刚开始使用Go,我发现自己在Go中寻找等效的map()和reduce()函数。我没有找到它们,所以重新开始循环。例如,这是我使用的而不是map(),其中mapFunction在别处定义:

data := make([]byte, 1024)
count, err := input.Read(data) // error handling removed from this snippet
for i:=0; i<count; i++ {
    data[i] = mapFunction(data[i])
}

这就是我使用的而不是reduce(),其中有2个状态变量,我用它来跟踪CSV中字段的引用,因为代码在切片中的每个项目中移动:

data := make([]byte, 1024)
count, err := input.Read(data) // error handling removed from this snippet
for i:=0; i<count; i++ {
    data[i], stateVariable1, stateVariable2 =
        reduceFunction(data[i], stateVariable1, stateVariable2)
}

以下是我的问题:

  1. 我错过了内置的功能吗?
  2. 为每个片段使用可变片段是否合适?
  3. 使用goroutines作为map()会是个好主意吗?是否允许将IO操作分离以读取文件和在每个项目上运行映射函数的过程,从而允许并行化?
  4. 说goroutine不适合reduce()函数是正确的,因为2个状态变量是由所有前面的数据定义的,并且必须按顺序进行。换句话说,这个顺序过程无法从并发架构中受益?
  5. 谢谢!

    ps - 完整代码在这里:https://github.com/dbro/csvquote/blob/go/csvquote.go

2 个答案:

答案 0 :(得分:4)

简而言之:

  1. 不,没有内置地图或减少。
  2. 是。还有什么?
  3. 否。如果没有先前的测量或一些已证实的实际需要,甚至不要考虑这些东西。
  4. 再长一点。

    1. Go不起作用,没有map / reduce内置或标准库
    2. Go中有数组和切片。两者都是可变的。切片是大多数时候的自然选择。
    3. 过早优化...,但当然:阅读处理可以进入一个循环,将输入包装在bufio.Reader中可能是一个好主意。
    4. Goroutines很不错,它们允许不同类型的程序构造,但这并不意味着它们将被用于一切。通过引入goroutines,没有必要使完全清晰的for循环复杂化。

答案 1 :(得分:0)

Volker给出了一个很好的答案,但它并没有发挥Go的主要优势之一,即它的并发性。通过使用“服务器场”策略,可以并行化映射/减少类型的操作(过早优化)。这涉及将要完成的工作分成发送给单独工作人员(即goroutines)的工作包。 Map / Reduce是执行此操作的通用方法,需要更高阶的函数和不可变的数据结构。

Go足够灵活,即使它不是一种功能语言,也可以进行定制的并行分解。虽然没有不变性,但它允许通过使用复制语义来避免别名,从而消除了在goroutines之间交换值时的竞争条件,这实际上是好的。简单地说:共享时直接使用结构而不是指向结构的指针。 (为了帮助,Go1.1中有一个新的竞赛探测器)。

服务器场模式是实现高并行化效率的好方法,因为它是自平衡的。这与几何分解(即通过聚集区域并将它们分配给处理器来共享数据网格)和算法分解(即,将流水线中的不同阶段分配给不同处理器)形成对比,这两者都遭受潜在的不平衡负载。 Go能够表达这三种。