2

我正在测试 ruby​​、python 和 scala,看看哪个对大数组有更好的支持。

Ruby (each) -> 84 MB, 2s # a = [];(0...1e7).each{|i| a[i]=i}
Ruby (expand) -> 254 MB, 60s #a = [*(0...1e7)]
Python (numpy) -> 95 MB, < 1s # a = np.arange(0, 1e7)
Python (range) -> 391 MB, < 1s # a = list(range(0, int(1e7)))
Scala (range) -> Memory Limit Exceeded :-) # var a = Range(0, 1e7.toInt).map(_.toInt)

如您所见,使用scala时内存限制超过了,这是什么问题?!!!

--UPDATE

好的,我应该使用

var a = Array.range(0, 1e7.toInt)

但是,如果我想将数组映射到字符串呢?

var b = a.map(_.toString())

这里失败...

4

3 回答 3

4

Scala 的 Range 与纯粹意义上的数组并不完全相同(在它内部除了保留 N 项之外还做了一些额外的工作,因此它的内存效率较低并且消耗内存的速度更快)。

Array.range(0, 1e7.toInt)将更接近 python 的 np.arange 并且可以正常工作。

于 2013-04-25T08:58:06.200 回答
3

你想要一千万个典型长度为 7 的字符串(你也有一千万个整数),并且在 JVM 上的字符串每个字符两个字节(加上开销),所以你肯定需要至少 180 MB 来保存它。让我们看看它到底有多糟糕:

$ scala -J-Xmx896M -e 'println(Array.range(0,1e7.toInt).map(_.toString).apply(9999999))'
9999999

$ scala -J-Xmx832M -e 'println(Array.range(0,1e7.toInt).map(_.toString).apply(9999999))'
java.lang.OutOfMemoryError: Java heap space

所以你去; 比您预期的要差大约 4.5 倍。JVM 不太擅长这种事情:每个字符串实际上是两个对象(字符串和字符数组),一个对象大约有 12 个字节的开销加上内容,并且四舍五入到很好的边界。并且 JVM 本身需要一些空间来运行(并且对于它加载的所有类,尤其是使用 Scala 包括解释器)。所以这是“合理的”。

但是您不是在这里测试对大型数组的支持;您正在测试 Java 的内存效率如何String,但不是很好。

于 2013-04-25T11:18:23.413 回答
1

你的斯卡拉代码:

var a = Range(0, 1e7.toInt).map(_.toInt)

如果环境内存不足,将抛出“java.lang.OutOfMemoryError”异常——这可以正常工作。

您可能遇到的问题是您的 Scala 代码不会创建一个巨大的数组,它会创建一个巨大的IndexedSeq。在 Scala 中,IndexedSeq 就像 B 树。如果您想比较数组,请将您的 Scala 代码更改为以下内容,您可能会得到更好的结果。

val a = (0 to 1e7.toInt).toArray[Int]
于 2013-04-25T13:38:10.720 回答