From 48c52326ddb1c34c9d43bba4319f14f6aeaa8d25 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Mon, 9 Nov 2020 13:43:11 +0100 Subject: [PATCH] Update scaladocs --- .../scala/concurrent/BlockContext.scala | 8 +- .../scala/concurrent/ExecutionContext.scala | 81 +++++++++++++------ 2 files changed, 60 insertions(+), 29 deletions(-) diff --git a/src/library/scala/concurrent/BlockContext.scala b/src/library/scala/concurrent/BlockContext.scala index 5586400e85a2..e282a4125c33 100644 --- a/src/library/scala/concurrent/BlockContext.scala +++ b/src/library/scala/concurrent/BlockContext.scala @@ -13,12 +13,12 @@ package scala.concurrent /** - * A context to be notified by `scala.concurrent.blocking` when + * A context to be notified by [[scala.concurrent.blocking]] when * a thread is about to block. In effect this trait provides - * the implementation for `scala.concurrent.Await`. - * `scala.concurrent.Await.result()` and `scala.concurrent.Await.ready()` + * the implementation for [[scala.concurrent.Await]]. + * [[scala.concurrent.Await.result]] and [[scala.concurrent.Await.ready]] * locates an instance of `BlockContext` by first looking for one - * provided through `BlockContext.withBlockContext()` and failing that, + * provided through [[BlockContext.withBlockContext]] and failing that, * checking whether `Thread.currentThread` is an instance of `BlockContext`. * So a thread pool can have its `java.lang.Thread` instances implement * `BlockContext`. There's a default `BlockContext` used if the thread diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala index 46e5d527b7d1..cd4a7c6e3c27 100644 --- a/src/library/scala/concurrent/ExecutionContext.scala +++ b/src/library/scala/concurrent/ExecutionContext.scala @@ -32,8 +32,8 @@ import scala.annotation.implicitNotFound * While it is possible to simply import * `scala.concurrent.ExecutionContext.Implicits.global` to obtain an * implicit `ExecutionContext`, application developers should carefully - * consider where they want to set execution policy; - * ideally, one place per application—or per logically related section of code— + * consider where they want to define the execution policy; + * ideally, one place per application — or per logically related section of code — * will make a decision about which `ExecutionContext` to use. * That is, you will mostly want to avoid hardcoding, especially via an import, * `scala.concurrent.ExecutionContext.Implicits.global`. @@ -57,12 +57,12 @@ import scala.annotation.implicitNotFound * knowing that only that library's network operations will be affected. * Application callback execution can be configured separately. */ -@implicitNotFound("""Cannot find an implicit ExecutionContext. You might pass +@implicitNotFound("""Cannot find an implicit ExecutionContext. You might add an (implicit ec: ExecutionContext) parameter to your method. The ExecutionContext is used to configure how and on which -thread pools Futures will run, so the specific ExecutionContext -that is selected is important. +thread pools asynchronous tasks (such as Futures) will run, +so the specific ExecutionContext that is selected is important. If your application does not define an ExecutionContext elsewhere, consider using Scala's global ExecutionContext by defining @@ -121,23 +121,27 @@ trait ExecutionContextExecutorService extends ExecutionContextExecutor with Exec */ object ExecutionContext { /** - * The explicit global `ExecutionContext`. Invoke `global` when you want to provide the global - * `ExecutionContext` explicitly. + * The global [[ExecutionContext]] This default `ExecutionContext` implementation is backed by a work-stealing thread + * pool. It can be configured via the following system properties: * - * The default `ExecutionContext` implementation is backed by a work-stealing thread pool. - * It can be configured via the following [[scala.sys.SystemProperties]]: - * - * `scala.concurrent.context.minThreads` = defaults to "1" - * `scala.concurrent.context.numThreads` = defaults to "x1" (i.e. the current number of available processors * 1) - * `scala.concurrent.context.maxThreads` = defaults to "x1" (i.e. the current number of available processors * 1) - * `scala.concurrent.context.maxExtraThreads` = defaults to "256" + * - `scala.concurrent.context.minThreads` = defaults to "1" + * - `scala.concurrent.context.numThreads` = defaults to "x1" (i.e. the current number of available processors * 1) + * - `scala.concurrent.context.maxThreads` = defaults to "x1" (i.e. the current number of available processors * 1) + * - `scala.concurrent.context.maxExtraThreads` = defaults to "256" * * The pool size of threads is then `numThreads` bounded by `minThreads` on the lower end and `maxThreads` on the high end. * * The `maxExtraThreads` is the maximum number of extra threads to have at any given time to evade deadlock, - * see [[scala.concurrent.BlockContext]]. + * see [[scala.concurrent.blocking]]. + * + * The `global` execution context can be used explicitly, by defining an + * `implicit val ec = ExecutionContext = ExecutionContext.global`, or by importing + * [[ExecutionContext.Implicits.global]]. + * + * @note Asynchronous code with short-lived nested tasks is executed more efficiently when using + * [[ExecutionContext.opportunistic]]. * - * @return the global `ExecutionContext` + * @return the global [[ExecutionContext]] */ final lazy val global: ExecutionContextExecutor = impl.ExecutionContextImpl.fromExecutor(null: Executor) @@ -167,11 +171,42 @@ object ExecutionContext { } /** - * This `ExecutionContext` is ideally suited to execute short-lived tasks on the `global` `ExecutionContext` as it - * attempts to locally batch the execution of nested tasks. + * This `ExecutionContext` uses the same thread pool as [[ExecutionContext.global]]. It attempts to batch nested + * task and execute them on the same thread as the enclosing task. This is ideally suited to execute short-lived tasks + * as it reduces the overhead of context switching. * - * WARNING: long-running and/or blocking tasks should be demarcated within `scala.concurrent.blocking`-blocks, + * WARNING: long-running and/or blocking tasks should be demarcated within [[scala.concurrent.blocking]]-blocks * to ensure that any pending tasks in the current batch can be executed by another thread on `global`. + * + * === How to use === + * + * This `ExecutionContext` is `private[scala]` to maintain binary compatibility. It was added in 2.13.3, code that + * uses it will fail to run with a 2.13.0-2 Scala library. + * + * Libraries should not reference this field because users of the library might be using an earlier Scala version. + * + * Application authors can safely use the field because the Scala version at run time is the same as at compile time. + * Options to bypass the access restriction include: + * + * 1. Using a structural type (see below). This uses reflection at run time. + * 1. Writing a Scala `object` in the `scala` package (see below). + * 1. Writing a Java source file. This works because `private[scala]` is emitted as `public` in Java bytecode. + * + * {{{ + * // Option 1 + * implicit lazy val ec: ExecutionContext = + * (scala.concurrent.ExecutionContext: + * {def opportunistic: scala.concurrent.ExecutionContextExecutor} + * ).opportunistic + * + * // Option 2 + * package scala { + * object OpportunisticEC { + * implicit lazy val ec: scala.concurrent.ExecutionContext = + * scala.concurrent.ExecutionContext.opportunistic + * } + * } + * }}} */ private[scala] lazy val opportunistic: ExecutionContextExecutor = new ExecutionContextExecutor with BatchingExecutor { final override def submitForExecution(runnable: Runnable): Unit = global.execute(runnable) @@ -187,12 +222,8 @@ object ExecutionContext { object Implicits { /** - * The implicit global `ExecutionContext`. Import `global` when you want to provide the global - * `ExecutionContext` implicitly. - * - * The default `ExecutionContext` implementation is backed by a work-stealing thread pool. By default, - * the thread pool uses a target number of worker threads equal to the number of - * [[https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#availableProcessors-- available processors]]. + * An accessor that can be used to import the global `ExecutionContext` into the implicit scope, + * see [[ExecutionContext.global]]. */ implicit final def global: ExecutionContext = ExecutionContext.global }