首页 文章

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

提问于
浏览
11

This answer指示如何将 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

我的问题与评论中提出的问题相同:

未来有什么问题?为什么你使用额外的线程与Promise结合?

答案如下:

它会阻止线程拉动中的线程 . 如果您为这样的期货配置了ExecutionContext,那很好,但是默认的ExecutionContext包含与处理器一样多的线程 .

我不确定我理解这个解释 . 重申:

future { jfuture.get } 有什么问题?在手中创建一个新线程并在那里阻塞时,在未来内部是否阻塞?如果没有,它有什么不同?

2 回答

  • 7

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

    默认线程池中有许多踏板,因为有许多处理器 .

    使用 jfuture.get ,您将获得1个线程被阻止 .

    设's assume you have 8 processors. Also let'假设每个 jfuture.get 需要10秒钟 . 现在创建8 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
    

    对于 2+2 评估,10秒有点太长了 .

    所有其他 future 和同一执行上下文中的所有actor将被停止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 {... 实现 blockingFuture ,但是额外的执行上下文允许您限制线程数 .

  • 8

    它实际上非常简单 . scala.concurrent.PromiseFuture 的具体实现,注定是异步计算 .

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

    Thread 将阻塞,直到 jfuture 内的计算完成 . get 方法正在阻止 .

    阻塞意味着在计算完成之前,其他任何内容都不会发生 . 你本质上是在垄断 Thread ,看起来像是一个间歇性地检查结果的 while 循环 .

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

    特别:

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

    当阻塞无法避免时,通常的做法是生成 new Threadnew Runnablenew Callable 以允许计算执行/独占子线程 .

    在示例中@senia给出:

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

    这与 future {jfuture.get} 有什么不同?它不会阻止由Scala提供的默认值 ExecutionContext ,它具有与机器处理器一样多的线程 .

    这意味着代码中的所有其他期货将始终等待 future { jfuture.get } 完成,因为整个上下文被阻止 .

相关问题