一.引言
scala 开发中常常需要遍历数组,一般有 Array 的 foreach 或者使用 Iterator 的 hasNext 和 next 方法进行遍历,小数据量情况下二者使用差别不大,foreach 更便利,但切换到大数据后,二者的性能和运行情况出现较大差异,下面用两个例子简单看看。
二. Iterator 与 Array
1.内存分析
toArray: 将此可遍历或迭代器的所有元素复制到缓冲区。注意:对于无限大小的集合不会终止。
toIterator: 返回此iterable集合中元素的迭代器。生成与迭代器相同的结果。
前者会将所有元素复制到缓存区,所以大数据量下会占用很多内存,后者返回迭代器,数据持续读出,所以占用内存少。
2.小数据量遍历
// Array 遍历
val num = (0 to 100000000).toArray
num.foreach(println(_))
// Iterator 遍历
val num = (0 to 100000000).toIterator
num.foreach(println(_))
通过内存监控可以看到二者在运行时的区别,
3.大数据量遍历
val num = (0 to 1000000000).toArray
num.foreach(println(_))
val num = (0 to 1000000000).toIterator
num.foreach(println(_))
toArray 直接内存溢出
toIterator 则正常运行
三.总结
Iterator 和 Array 使用时内存占用不同,但根据使用场景的不同二者也各有优劣,逐条数据遍历时 如果内存资源比较紧张可以考虑 Iterator,如果需要全局统计或者一次使用全部数据时则使用 Array,当然如果只计数也可以采用 Iterator + Counter 的模式。大数据开发场景中最常见的迭代器就是 RDD,之所以很大的数据量 Spark 也不会 oom,就是因为 RDD 采用 Iterator 的模式,如果需要放到内存则需要触发 action 算子例如 take,collect,cache,persist ,它们会把 RDD 数据拉到内存,这个时候就有可能触发 oom,撑爆内存。