Golang效率中的非通用映射

时间:2014-01-04 00:56:42

标签: generics map go

我完全理解Go不提供对泛型的支持,而是选择用户在需要时创建自己的特定于类型的方法。

但是,我想知道是否有更有效的方法在数据结构上创建特定的map函数,而不涉及遍历整个列表并应用该函数,或者这是其他语言< em> with generics support 在幕后做。

示例:

func map(list []string, op func(string)string) []string {
  ouput := make([]string, len(list))
  for i, v := range list {
    output[i] = op(v)
  }
  return output
}

谢谢!

2 个答案:

答案 0 :(得分:4)

仅供参考,map是保留字,因此您不能完全按照小写map编写函数。

这可能就像你能得到的一样好。泛型不会让你分配新内存。

使用append()稍微快一些,而不是在开始时将整个切片初始化为空字符串。例如:

func Map(list []string, op func(string) string) []string {
   output := make([]string, 0, len(list))
   for _, v := range list {
      output = append(output, op(v))
   }
   return output
}

这让我的速度提高了10%。

更新:这对于很短的切片来说才是真的。这是一个更彻底的基准 - 在更长的切片上使用追加实际上更慢。我也试过并行化,这只是在更大的切片上的开销。

代码: https://gist.github.com/8250514

输出(测试名称末尾的数字是切片长度):

go test -bench=".*" -test.cpu=2
BenchmarkSliceMake10-2       5000000           473 ns/op
BenchmarkSliceMake100-2       500000          3637 ns/op
BenchmarkSliceMake1000-2       50000         43920 ns/op
BenchmarkSliceMake10000-2       5000        539743 ns/op
BenchmarkSliceAppend10-2     5000000           464 ns/op
BenchmarkSliceAppend100-2     500000          4303 ns/op
BenchmarkSliceAppend1000-2     50000         51172 ns/op
BenchmarkSliceAppend10000-2     5000        595650 ns/op
BenchmarkSlicePar10-2         500000          3784 ns/op
BenchmarkSlicePar100-2        200000          7940 ns/op
BenchmarkSlicePar1000-2        50000         50118 ns/op
BenchmarkSlicePar10000-2        5000        465540 ns/op

答案 1 :(得分:3)

是的,通常这正是泛型用于的东西。如果你愿意,这些函数仍然可以使用反射在Go中编写,尽管它们很多更慢。例如,请参阅我的github.com/synful/illegal/generics包,它使用反射来实现经典的泛型函数。我实际上并没有对这些进行基准测试,但如果它们与您提供的特定类型实现的性能接近,我会感到非常惊讶。

编辑:只是为了踢,我复制了Wes Freeman的第一个测试,并在我的基于反射的Map上运行它。这是在一个相当不足的服务器上运行,但仍然。结果不言自明(根据Wes的结果衡量缓慢)。

BenchmarkSliceMake10-2    200000         14091 ns/op [30.0x    slower]
BenchmarkSliceMake100-2    10000        112137 ns/op [30.83x   slower]
BenchmarkSliceMake1000-2    2000       1177498 ns/op [26.810x  slower]
BenchmarkSliceMake10000-2    100      11513085 ns/op [21.3307x slower]

注意:我特别使用了这个测试,因为我的实现预先分配了切片。