Skip to content

Commit

Permalink
Update scaladocs
Browse files Browse the repository at this point in the history
  • Loading branch information
lrytz committed Nov 13, 2020
1 parent 94390f0 commit 0044904
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 31 deletions.
8 changes: 4 additions & 4 deletions src/library/scala/concurrent/BlockContext.scala
Expand Up @@ -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
Expand Down
104 changes: 77 additions & 27 deletions src/library/scala/concurrent/ExecutionContext.scala
Expand Up @@ -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 applicationor per logically related section of code—
* consider where they want to define the execution policy;
* ideally, one place per applicationor 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`.
Expand All @@ -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
Expand Down Expand Up @@ -121,23 +121,81 @@ 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: scala.concurrent.ExecutionContext = scala.concurrent.ExecutionContext.global`, or by importing
* [[ExecutionContext.Implicits.global]].
*
* == Batching short-lived nested tasks ==
*
* Asynchronous code with short-lived nested tasks is executed more efficiently when using
* `ExecutionContext.opportunistic` (continue reading to learn why it is `private[scala]` and how to access it).
*
* `ExecutionContext.opportunistic` 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
* to ensure that any pending tasks in the current batch can be executed by another thread on `global`.
*
* === How to use ===
*
* This field is `private[scala]` to maintain binary compatibility. It was added in 2.13.4, code that references it
* directly fails to run with a 2.13.0-3 Scala library.
*
* @return the global `ExecutionContext`
* Libraries should not reference this field directly because users of the library might be using an earlier Scala
* version. In order to use the batching `ExecutionContext` in a library, the code needs to fall back to `global`
* in case the `opportunistic` field is missing (example below). The resulting `ExecutionContext` has batching
* behavior in all Scala 2.13 versions (`global` is batching in 2.13.0-3).
*
* {{{
* implicit val ec: scala.concurrent.ExecutionContext = try {
* scala.concurrent.ExecutionContext.getClass
* .getDeclaredMethod("opportunistic")
* .invoke(scala.concurrent.ExecutionContext)
* .asInstanceOf[scala.concurrent.ExecutionContext]
* } catch {
* case _: NoSuchMethodException =>
* scala.concurrent.ExecutionContext.global
* }
* }}}
*
* 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 (example below). This uses reflection at run time.
* 1. Writing a Scala `object` in the `scala` package (example below).
* 1. Writing a Java source file. This works because `private[scala]` is emitted as `public` in Java bytecode.
*
* {{{
* // Option 1
* implicit val ec: scala.concurrent.ExecutionContext =
* (scala.concurrent.ExecutionContext:
* {def opportunistic: scala.concurrent.ExecutionContextExecutor}
* ).opportunistic
*
* // Option 2
* package scala {
* object OpportunisticEC {
* implicit val ec: scala.concurrent.ExecutionContext =
* scala.concurrent.ExecutionContext.opportunistic
* }
* }
* }}}
*
* @return the global [[ExecutionContext]]
*/
final lazy val global: ExecutionContextExecutor = impl.ExecutionContextImpl.fromExecutor(null: Executor)

Expand Down Expand Up @@ -167,11 +225,7 @@ 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.
*
* 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`.
* See [[ExecutionContext.global]].
*/
private[scala] lazy val opportunistic: ExecutionContextExecutor = new ExecutionContextExecutor with BatchingExecutor {
final override def submitForExecution(runnable: Runnable): Unit = global.execute(runnable)
Expand All @@ -187,12 +241,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
}
Expand Down

0 comments on commit 0044904

Please sign in to comment.