【发布时间】:2014-04-16 11:55:52
【问题描述】:
我发现这有点令人困惑。我认为 scala 中的期货是不可变的容器,一旦设置,总是返回相同的值。
所以我有一个未来:
val y = future {Thread.sleep(1000); 1};
现在当我立即(在未来解决之前)将它传递给Await.result 块两次:
Await.result(for (r1 <- y; r2 <- y) yield (r1, r2), 60 seconds)
我收到了TimetoutException。
但是,如果我在未来解决后这样做,一切都会正常工作并按预期返回(1,1)。
这种行为的原因是什么?
编辑:
我正在使用隐式 ExecutionContext.Implicits.global 和 scala.concurrent @ scala 2.10.3
编辑2: 如果我创建另一个未来实例做同样的事情并对它们执行 Await.result ,它不会阻塞。
【问题讨论】:
-
如果 C# 中的
async/await教会了我一些东西,那就是混合同步和异步等待是一个坏主意,而且往往会导致死锁。我怀疑在阻塞Await.result、异步未来和阻塞Thread.sleep之间存在死锁。 -
@PatrykĆwiek 是的,它过于简单化了,但由于 99% 的期货示例使用
Thread.sleep我认为应该没有问题。特别是因为无法确定我将来使用的库代码不会自己调用Thread.sleep。 -
这些示例使用
Thread.sleep仅仅是因为标准库中没有直接的工具来安排/暂停未来,所以这是演示需要这种安排的东西的最简单方法。但是你绝对不应该在生产代码中使用它,因为它会阻塞整个线程,完全破坏使用未来的性能优势,而且可能会阻止其他毫无戒心的未来执行(当所有未来的线程都在休眠时)。只是不要这样做。 -
除非您必须执行文件 I/O 或 DNS 或 JDBC 或调用各种 AWS SDK 类之类的阻塞库或...... “但它通常是一种实际需要。当出现这些情况时,您需要创建自己的
ExecutionContex并由适当的ThreadPool支持,以确保您的系统不会停止、未充分利用 CPU 或其他行为不端。 -
@RégisJean-Gilles 我知道我不应该在生产中使用它,很难确定是否某些第三方解决方案不这样做。另外我想知道为什么会这样?我是不是很不幸,以至于所有期货都由全局执行上下文中的同一个线程执行?这可以解释这种行为。即使在 Thread.sleep 退出时也会发生这种情况,所以我不知道什么可以真正阻止这里的事情。
标签: scala concurrency