简体   繁体   English

Scala Future.sequence(Iterator) 抛出 NoSuchElementException

[英]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.这是因为itit2不同步: 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!结果it2next()hasNext不同步,这是一团糟!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM