Scala中Iterator容許執行一次

背景java

  使用spark執行mapPartitionsWithIndex((index,iterator)=>{....}),在執行體中將iterator進行一次迭代後,再次根據iterator執行迭代,iterator迭代體未執行。express

猜測及驗證過程緩存

  猜想iterator只能執行一次迭代。函數

  測試例子以下:測試

val rdd1 = sc.makeRDD(1 to 10,2)
val rdd2 = rdd1.mapPartitionsWithIndex{(index,iterator)=>{
	var result = List[String]()
	var sum = 0
	var count = 0
	while(iterator.hasNext){
		sum += iterator.next()
	}
	while(iterator.hasNext){
		count += 1
	}
	result.::(index + "|" + sum + "|" + count).iterator
}}

執行結果
res0: Array[String] = Array(0|15|0, 1|40|0)

   經過執行結果能夠看出sum執行了求和運算,count沒有執行統計數量運算或未正確執行統計數量運算,推測可能的緣由:1. iterator可以重複執行迭代,可是count的算術運算出現問題;2.iterator只能執行一次迭代;spa

  對緣由1的驗證例子:scala

val rdd1 = sc.makeRDD(1 to 10,2)
val rdd2 = rdd1.mapPartitionsWithIndex{(index,iterator)=>{
	var result = List[String]()
	var sum = 0
	var count = 0
	while(iterator.hasNext){
		sum += iterator.next()
                count += 1
	}
	result.::(index + "|" + sum + "|" + count).iterator
}}

執行結果
res0: Array[String] = Array(0|15|5, 1|40|5)

  若是iterator可以重複執行迭代,可是count的統計數量計算出現問題,那麼將sum和count放在同一個迭代體中,執行結果會和在兩個迭代體中執行結果一致。可是執行結果倒是可以正常的統計出數量,證實了推測緣由1不成立。blog

  對緣由2的驗證例子:it

  爲了單純的驗證是iterator執行問題,下邊的例子去掉了spark相關的函數spark

val iterator = Iterator(1,2,3,4,5,6,7)
var sum = 0
while(iterator.hasNext){
	sum += iterator.next
}
println("sum is " + sum)
val expression = if(iterator.isEmpty) "iterator is empty" else "iterator is not empty"
println(expression)

  若是iterator只能執行一次迭代的話,expression的結果是【iterator is empty】,真實執行結果以下

sum is 28
iterator is empty
iterator: Iterator[Int] = empty iterator
sum: Int = 28
expression: String = iterator is empty

  經過執行結果能夠看出,expression的結果確實是【iterator is empty】,因此推測緣由2成立。

結論

  scala中iterator只能執行一次迭代,若是須要屢次執行同一個迭代體,建議調用iterator.toList等方法,將迭代體轉化爲集合,再執行上述的驗證例子就會正常。

擴展

  1.iterator.min和iterator.max一樣是經過迭代得到,因此對於同一個iterator的min和max只能獲取一個。

  2.java中Iterator類同scala的Iterator,只容許進行一次迭代,若是須要進行屢次迭代,須要將iterator轉化爲集合類

  3.C#中沒有Iterator類,可是有IEnumerator,這個類能夠經過IEnumerator.Reset方法來重置,迭代完進行重置就能夠再次迭代,而對於java和scala的Iterator沒有類似的方法;

補充

  spark的mapPartitionsWithIndex中iterator儘可能不要使用toList,緣由:toList至關於將迭代數據進行了緩存,容易致使OutOfMemory的異常,iterator是流式的處理,處理完一條記錄纔會去讀取下一條記錄而且會丟棄已讀的記錄,沒法重複使用;而iterator.toList會將全部的記錄進行緩存,便於重複使用。

相關文章
相關標籤/搜索