2

来自 python 背景,刚从 Go 开始,我发现自己在 Go 中寻找 map() 和 reduce() 函数的等价物。我没有找到它们,所以又回到了 for 循环。例如,这是我使用的而不是 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. 为 map() 使用 goroutine 是个好主意吗?这是否允许将读取文件的 IO 操作与在每个项目上运行映射函数的进程解耦,从而允许并行化?
  4. 说 goroutine 不适合 reduce() 函数是否正确,因为 2 个状态变量是由所有前面的数据定义的,并且它必须按顺序进行。换句话说,这个顺序过程不能从并发架构中受益吗?

谢谢!

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

4

2 回答 2

4

简而言之:

  1. 不,没有内置的 map 或 reduce。
  2. 是的。还有什么?
  3. 不。在没有事先测量或一些被证明的真正需要的情况下,甚至不要考虑这些东西。
  4. 是的。

有点长。

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

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

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

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

于 2013-05-19T22:21:47.960 回答