[英]Scala Future.sequence(Iterator) throws NoSuchElementException
Why is the following code throwing java.util.NoSuchElementException: next on empty iterator
???为什么以下代码
java.util.NoSuchElementException: next on empty iterator
???
implicit val ec = ExecutionContext.global
val it = (0 until 10).toIterator.map{
x =>
Thread.sleep(500)
println(x)
x
}
val it2 = new Iterator[Future[Int]] {
def hasNext = it.hasNext
def next() = Future { blocking { it.next() } }
} //This should be equivalent to it.map{x => Future{blocking{x}}}
Await.result(Future.sequence(it2), Inf)
Subsidiary question: why is it2
not behaving as it.map{x => Future{blocking{x}}}
??附属问题:为什么
it2
的行为不像it.map{x => Future{blocking{x}}}
?
You have a concurrency error, someone calls hasNext
it returns true
because the underlying iterator is capable of producing new elements.您有一个并发错误,有人调用
hasNext
它返回true
,因为底层迭代器能够生成新元素。 Then it calls next
this returns a future that when completed will hold the next
value.然后它调用
next
这返回一个未来,完成后将保存next
值。
However, for the caller (in this case Future.sequence
) it already finished so it calls hasNext
again which will return true
again but because the underlying iterator hasn't finished producing the first element so we produce a second that is enqueued until the first one finish (so you win nothing with the future) .但是,对于调用者(在本例中
Future.sequence
) ,它已经完成,所以它再次调用hasNext
,这将再次返回true
但是因为底层迭代器尚未完成第一个元素的生成,所以我们生成第二个,该第二个被排入队列直到第一个一次完成(所以你在未来一无所获) 。
And this continues creating more and more and more futures that will eventually call next
and get a NoSuchElementException
because the underlying iterator didn't have more elements but you already create more and more futures waiting for more and more elements.这继续创建越来越多的期货,最终将调用
next
并获得NoSuchElementException
,因为底层迭代器没有更多元素,但您已经创建了越来越多的期货等待越来越多的元素。
So, in other words, you are getting a true
in hasNext
just because it hasn't finished producing elements and as such haven't mutated its internal state;所以,换句话说,你在
hasNext
中得到了一个true
只是因为它还没有完成生产元素,因此没有改变它的内部 state; not because it actually has more elements.不是因为它实际上有更多的元素。
This is a good recordatory that mutability + concurrency = headaches.这是一个很好的记录,可变性 + 并发性 = 头痛。
Again, I recommend you to use an appropriate abstraction for thi同样,我建议您使用适当的抽象来实现
The other answer is pointing to the right direction, but I just rephrase it a bit more cleanly.另一个答案是指向正确的方向,但我只是更清楚地改写它。 By adding some printouts in
next()
and hasNext
methods, one can see that they are called continuously.通过在
next()
和hasNext
方法中添加一些打印输出,可以看到它们被连续调用。 This is because the it
and it2
gets out-of-sync: it.next()
is blocking, while it2.next()
is not, but it2.hasNext == it.hasNext
, so it2.hasNext
is blocking.这是因为
it
和it2
不同步: it.next()
被阻塞,而it2.next()
不是,但it2.hasNext == it.hasNext
,所以it2.hasNext
被阻塞。 As a result it2
has its next()
and hasNext
out-of-sync which is a mess!结果
it2
的next()
和hasNext
不同步,这是一团糟!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.