https://github.com/scala/scala-async
An asynchronous programming facility for Scala
https://github.com/scala/scala-async
asynchronous concurrency scala scala-async
Last synced: 20 days ago
JSON representation
An asynchronous programming facility for Scala
- Host: GitHub
- URL: https://github.com/scala/scala-async
- Owner: scala
- License: apache-2.0
- Created: 2013-04-01T22:22:27.000Z (about 12 years ago)
- Default Branch: main
- Last Pushed: 2024-10-26T20:00:36.000Z (6 months ago)
- Last Synced: 2024-10-29T15:37:18.377Z (6 months ago)
- Topics: asynchronous, concurrency, scala, scala-async
- Language: Scala
- Size: 1.73 MB
- Stars: 1,147
- Watchers: 55
- Forks: 92
- Open Issues: 13
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# scala-async [
](http://search.maven.org/#search%7Cga%7C1%7Cg%3Aorg.scala-lang.modules%20a%3Ascala-async_2.12) [
](http://search.maven.org/#search%7Cga%7C1%7Cg%3Aorg.scala-lang.modules%20a%3Ascala-async_2.13)
A Scala DSL to enable a direct style of coding when composing `Future`s.
## Usage
As of scala-async 1.0, Scala 2.12.12+ or 2.13.3+ are required.
### Add dependency
#### SBT Example
```scala
libraryDependencies += "org.scala-lang.modules" %% "scala-async" % "1.0.1"
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided
```For Maven projects add the following to your (make sure to use the correct Scala version suffix
to match your project’s Scala binary version):#### Maven Example
```scala
org.scala-lang.modules
scala-async_2.13
1.0.1org.scala-lang
scala-reflect
2.13.8
provided```
### Enable compiler support for `async`
Add the `-Xasync` to the Scala compiler options.
#### SBT Example
```scala
scalacOptions += "-Xasync"
```#### Maven Example
```xml
...
net.alchim31.maven
scala-maven-plugin
4.4.0
-Xasync
...```
### Start coding
```scala
import scala.concurrent.ExecutionContext.Implicits.global
import scala.async.Async.{async, await}val future = async {
val f1: Future[Boolean] = async { ...; true }
val f2 = async { ...; 42 }
if (await(f1)) await(f2) else 0
}
```## What is `async`?
`async` marks a block of asynchronous code. Such a block usually contains
one or more `await` calls, which marks a point at which the computation
will be suspended until the awaited `Future` is complete.By default, `async` blocks operate on `scala.concurrent.{Future, Promise}`.
The system can be adapted to alternative implementations of the
`Future` pattern.Consider the following example:
```scala
def slowCalcFuture: Future[Int] = ... // 01
def combined: Future[Int] = async { // 02
await(slowCalcFuture) + await(slowCalcFuture) // 03
}
val x: Int = Await.result(combined, 10.seconds) // 05
```Line 1 defines an asynchronous method: it returns a `Future`.
Line 2 begins an `async` block. During compilation,
the contents of this block will be analyzed to identify
the `await` calls, and transformed into non-blocking
code.Control flow will immediately pass to line 5, as the
computation in the `async` block is not executed
on the caller's thread.Line 3 begins by triggering `slowCalcFuture`, and then
suspending until it has been calculated. Only after it
has finished, we trigger it again, and suspend again.
Finally, we add the results and complete `combined`, which
in turn will release line 5 (unless it had already timed out).It is important to note that while lines 1-4 are non-blocking,
they are not parallel. If we wanted to parallelize the two computations,
we could rearrange the code as follows:```scala
def combined: Future[Int] = async {
val future1 = slowCalcFuture
val future2 = slowCalcFuture
await(future1) + await(future2)
}
```## Limitations
### `await` must be directly in the control flow of the async expression
The `await` cannot be nested under a local method, object, class or lambda:
```
async {
List(1).foreach { x => await(f(x) } // invalid
}
```### `await` must be not be nested within `try` / `catch` / `finally`.
This implementation restriction may be lifted in future versions.
## Comparison with direct use of `Future` API
This computation could also be expressed by directly using the
higher-order functions of Futures:```scala
def slowCalcFuture: Future[Int] = ...
val future1 = slowCalcFuture
val future2 = slowCalcFuture
def combined: Future[Int] = for {
r1 <- future1
r2 <- future2
} yield r1 + r2
```The `async` approach has two advantages over the use of
`map` and `flatMap`:
1. The code more directly reflects the programmer's intent,
and does not require us to name the results `r1` and `r2`.
This advantage is even more pronounced when we mix control
structures in `async` blocks.
2. `async` blocks are compiled to a single anonymous class,
as opposed to a separate anonymous class for each closure
required at each generator (`<-`) in the for-comprehension.
This reduces the size of generated code, and can avoid boxing
of intermediate results.