我注意到如果我在RDD上应用mapPartitions
,分区将获得一个可迭代对象。在mapPartitions
函数中,然后我调用iterable的toArray
成员函数将该可迭代对象转换为Array对象。调用toArray
是否涉及复制,还是只是开始引用与数组相同的内存部分?如果涉及复制,有什么方法可以防止复制?
答案 0 :(得分:3)
对您的问题进行了一次重要更正 - mapPartitions
期间公开的分区数据结构是迭代器,而不是Iterable。这是界面差异:
Iterator
具有next()
和hasNext()
方法,可让您访问集合中的每个元素一次。一旦调用迭代器的next()
方法,最后一个元素就消失了(除非你把它存储在变量中)。Iterable
可以随时生成Iterator
。这使您可以根据需要多次访问每个元素。在实施方面,Iterator
可以流式传输数据。你真的只需要一次在内存中有一个元素,在调用next()
时加载。如果您正在使用Spark(sc.textFile
)读取文本文件,那么它就是这样做的,并且几乎不使用任何内存来进行简单的迭代迭代。
您绝对可以致电iterator.toArray
,但您可能不想这样做。你最终将所有数据推入内存(Spark一次只能加载一个元素,因为你一次要求所有这些元素),并复制每一段数据(对于基元,如{ {1}})或为每个数据分配一个新的引用(对于Int
,如AnyRef
)。没有办法阻止这种复制。
有时将分区迭代器转换为数组是您想要做的事情,但这些用例很少见。由于不必要的分配和GC,您可能会因内存不足而导致应用程序运行速度变慢,因此请仔细考虑是否真的需要它!