Scala全局ExecutionContext与ExecutionContextExecutorService的区别

5

我正在使用默认全局上下文和自己的ExecutionContext玩scala Futures。

我很好奇,当所有执行完成后,全局上下文(global context)是如何关闭的。因为如果我创建自己的ExecutionContext,我必须手动关闭它。

例如,

1)使用全局executionContext:

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}

object ParallelTasksWithGlobalExecutionContext {

  private val data: Iterable[Input] = Iterable("data1", "data2", "data3")

  def main(args: Array[String]): Unit = {

    val f: Future[Unit] = Future.traverse(data) { d =>

      println(s"[${Thread.currentThread().getName}]-Firing $d")
      processData(d)

    } map { processed =>
      processed.foreach(p => println(s"""[${Thread.currentThread().getName}]-$p"""))
    }

    Await.result(f, Duration.Inf)
  }

  type Input = String
  type Output = String

  def processData: (Input => Future[Output]) = data => {
    Future {
      Thread.sleep(5000)
      s"[Thread-${Thread.currentThread().getName}] data $data is processed."
    }
  }
}

输出

$ sbt "runMain ParallelTasksWithGlobalExecutionContext"
[info] Running ParallelTasksWithGlobalExecutionContext 
[run-main-0]-Firing data1
[run-main-0]-Firing data2
[run-main-0]-Firing data3
[scala-execution-context-global-59]-[Thread-scala-execution-context-global-58] data data1 is processed.
[scala-execution-context-global-59]-[Thread-scala-execution-context-global-59] data data2 is processed.
[scala-execution-context-global-59]-[Thread-scala-execution-context-global-60] data data3 is processed.
[success] Total time: 6 s, completed Apr 1, 2018 12:44:36 AM

执行完成后,应用程序终止。

2) 使用自己的ExecutionContext - 应用程序在所有执行完成后不会终止,直到我手动.shutdown

import java.util.concurrent.Executors

import scala.concurrent.{ExecutionContext, ExecutionContextExecutorService, Future}
import scala.util.{Failure, Success}

object ParallelTasksWithCustomExecutionContext {

  private val data: Iterable[Input] = Iterable("data1", "data2", "data3")
  implicit val singleThreadContext: ExecutionContextExecutorService = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(3))

  def main(args: Array[String]): Unit = {

    Future.traverse(data) { d =>

      println(s"[${Thread.currentThread().getName}]-Firing $d")
      processData(d)

    } onComplete {
      case Success(processed) =>
        processed.foreach(p => println(s"""[${Thread.currentThread().getName}]-$p"""))
        //singleThreadContext.shutdown()
      case Failure(f) =>
        f.printStackTrace()
        //singleThreadContext.shutdown()
    }

  }

  type Input = String
  type Output = String

  def processData: (Input => Future[Output]) = data => {
    Future {
      Thread.sleep(5000)
      s"[Thread-${Thread.currentThread().getName}] data $data is processed."
    }
  }
}

输出

$ sbt "runMain ParallelTasksWithCustomExecutionContext"
[info] Running ParallelTasksWithCustomExecutionContext 
[run-main-0]-Firing data1
[run-main-0]-Firing data2
[run-main-0]-Firing data3
[pool-7-thread-1]-[Thread-pool-7-thread-1] data data1 is processed.
[pool-7-thread-1]-[Thread-pool-7-thread-2] data data2 is processed.
[pool-7-thread-1]-[Thread-pool-7-thread-3] data data3 is processed.
<hangs>

这是JVisualVM线程监视器,

jvisual-vm

我的问题是,Scala的全局上下文如何在不询问客户端的情况下自动终止?

1个回答

2

Scala的global上下文是使用Thread工厂创建的,这使得Threads成为守护进程,因此它们(线程)不会阻止JVM在所有用户线程完成执行后退出。

请检查ExecutionContextImpl方法def createDefaultExecutorService(reporter: Throwable => Unit): ExecutorService


这就解释了。在这里也找到了答案 - Execution context without daemon threads for futures - prayagupa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接