当前位置: 首页 > 知识库问答 >
问题:

为什么是新线程而不是未来 {...}

阮桐
2023-03-14

此答案指示如何将java.util.concurrent.Future转换为scala.concurrent.Future,同时管理将发生阻塞的位置:

import java.util.concurrent.{Future => JFuture}
import scala.concurrent.{Future => SFuture}

val jfuture: JFuture[T] = ???
val promise = Promise[T]()
new Thread(
  new Runnable {
    def run() { promise.complete(Try{ jfuture.get }) }
  }
).start
val future = promise.future

我的问题和评论中的问题一样:

Future{jfuture.get}怎么了?为什么你使用一个额外的线程与Promise结合?

答复如下:

它会在你拉线的时候卡住线。如果您已经为这样的未来配置了ExecutionContext,这很好,但是默认的ExecutionContext包含的线程与您拥有的处理器一样多。

我不确定我是否理解这个解释。重申:

Future{jfuture.get}有什么问题?在未来内部阻塞不是和手动创建一个新线程并在那里阻塞一样吗?如果不是,有什么不同?

共有2个答案

彭建业
2023-03-14

其实挺简单的。< code > Scala . concurrent . promise 是< code>Future的具体实现,注定是异步计算。

当你想要转换时,使用jfuture.get,你正在运行一个阻塞计算,并输出一个立即解析的scala.concurrent.Future

< code >线程将阻塞,直到< code>jfuture内的计算完成。< code>get方法被阻止。

阻塞意味着在计算完成之前,线程内不会发生任何其他事情。在循环间歇检查结果时,您基本上垄断了线程

while (!isDone() && !timeout) {
   // check if the computation is complete
}

具体来说:

val jfuture: JFuture[T] = ??? // some blocking task

当无法避免阻塞时,通常的做法是生成一个新线程和一个新可运行new可调用,以允许计算执行/独占子线程。

在@senia给出的例子中:

new Thread(new Runnable { def run() {
  promise.complete(Try{ jfuture.get })
}}).start

这与未来{jfuture.get}有何不同?它不会阻止Scala提供的默认执行上下文,Scala的线程数与机器处理器的线程数相同。

这意味着代码中的所有其他未来都必须等待未来{jfuture.get}完成,因为整个上下文都被阻塞了。

羊昊苍
2023-03-14

future { jfuture.get }future { future { jfuture.get }} 之间几乎没有区别。

默认线程池中的胎面数量与处理器数量一样多。

使用< code>jfuture.get,您将有1个线程被阻塞。

假设您有8个处理器。我们还假设每个< code>jfuture.get需要10秒钟。现在创建8 < code > future { jfuture . get } 。

val format = new java.text.SimpleDateFormat("HH:mm:ss").format(_: Date)

val startTime = new Date
(1 to 8) map {_ => future{ Thread.sleep(10000) }}
future{
  2+2
  println(s"2+2 done. Start time: ${format(startTime)}, end time: ${format(new Date)}")
}

// 2+2 done. Start time: 20:48:18, end time: 20:48:28

10秒对于2 2评估来说有点长。

同一执行上下文中的所有其他< code>future和所有参与者将停止10秒钟。

使用附加执行上下文:

object BlockingExecution {
  val executor = ExecutionContext.fromExecutor(new ForkJoinPool(20))
}

def blockingFuture[T](f: => T) = {
  future( f )(BlockingExecution.executor)
}

val startTime = new Date
(1 to 8) map {_ => blockingFuture{ Thread.sleep(10000) }}
future{
  2+2
  println(s"2+2 done. Start time: ${format(startTime)}, end time: ${format(new Date)}")
}

// 2+2 done. Start time: 21:26:18, end time: 21:26:18

您可以使用new Thread(new Runnable {...)来实现阻塞未来,但额外的执行上下文允许您限制线程计数。

 类似资料:
  • 本文向大家介绍请为什么说js是单线程,而不是多线程呢?相关面试题,主要包含被问及请为什么说js是单线程,而不是多线程呢?时的应答技巧和注意事项,需要的朋友参考一下 JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。 JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript

  • 我正在通过quartz调度程序调用spring批处理作业,它应该每1分钟运行一次。当作业第一次运行时,成功打开ItemReader并运行作业。但是,当作业尝试第二次运行时,它使用的是第一次运行的相同实例,该实例已经初始化,并接收“java.lang.IllegalStateException:Stream is eignitialized.Close before re-opening”。我已经将

  • 问题内容: 我一直在寻找一些方法来轻松地对我的一些简单分析代码进行多线程处理,因为我注意到numpy仅使用一个内核,尽管事实上它应该是多线程的。 我知道numpy是为多个内核配置的,因为我可以看到使用numpy.dot的测试使用了我的所有内核,因此我只是将Mean重新实现为点积,并且运行速度更快。是否有某些原因意味着不能自己快速运行?我发现较大的数组具有类似的行为,尽管该比率比示例中显示的3接近2

  • 我试图理解背后的动机。如果已经存在类型类和,为什么有必要呢? 诚然,的实例是具体的类型,而的实例需要一个类型参数。(有关有用的解释,请参见Monoid vs MonadPlus。)但是你不能重写任何类型的约束吗 作为和的组合? 从。它的实施是: 我只能使用和实现它: 有人能澄清和之间的真正区别吗?

  • 参考Java的Fork/Join vs ExecutorService-何时使用哪个?,传统的线程池通常用于处理许多独立请求;用于处理连贯/递归任务,其中一个任务可能会产生另一个子任务并稍后加入。 那么,为什么Java-8的默认使用而不是传统的执行器? 在许多情况下,我们在或之后使用,然后提交一个函数式接口作为参数。从我的角度来看,这些任务是独立的,不是吗?

  • 问题内容: 这一直使我感到困惑。看起来这样会更好: 比这个: 是否有特定原因? 问题答案: 这是因为任何可迭代对象都可以连接(例如,列表,元组,字典,集合),但是其内容和“连接器” 必须是 字符串。 例如: 使用字符串以外的其他东西会引发以下错误: