docs for `join` and `noCancel`
This commit is contained in:
parent
1ff81c60ea
commit
8a306763ce
|
@ -4,6 +4,9 @@ Async/await is a programming model that relies on cooperative multitasking to
|
||||||
coordinate the concurrent execution of procedures, using event notifications
|
coordinate the concurrent execution of procedures, using event notifications
|
||||||
from the operating system or other treads to resume execution.
|
from the operating system or other treads to resume execution.
|
||||||
|
|
||||||
|
Code execution happens in a loop that alternates between making progress on
|
||||||
|
tasks and handling events.
|
||||||
|
|
||||||
<!-- toc -->
|
<!-- toc -->
|
||||||
|
|
||||||
## The dispatcher
|
## The dispatcher
|
||||||
|
@ -118,7 +121,8 @@ The `CancelledError` will now travel up the stack like any other exception.
|
||||||
It can be caught for instance to free some resources and is then typically
|
It can be caught for instance to free some resources and is then typically
|
||||||
re-raised for the whole chain operations to get cancelled.
|
re-raised for the whole chain operations to get cancelled.
|
||||||
|
|
||||||
Alternatively, the cancellation request can be translated to a regular outcome of the operation - for example, a `read` operation might return an empty result.
|
Alternatively, the cancellation request can be translated to a regular outcome
|
||||||
|
of the operation - for example, a `read` operation might return an empty result.
|
||||||
|
|
||||||
Cancelling an already-finished `Future` has no effect, as the following example
|
Cancelling an already-finished `Future` has no effect, as the following example
|
||||||
of downloading two web pages concurrently shows:
|
of downloading two web pages concurrently shows:
|
||||||
|
@ -127,8 +131,84 @@ of downloading two web pages concurrently shows:
|
||||||
{{#include ../examples/twogets.nim}}
|
{{#include ../examples/twogets.nim}}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Ownership
|
||||||
|
|
||||||
|
When calling a procedure that returns a `Future`, ownership of that `Future` is
|
||||||
|
shared between the callee that created it and the caller that waits for it to be
|
||||||
|
finished.
|
||||||
|
|
||||||
|
The `Future` can be thought of as a single-item channel between a producer and a
|
||||||
|
consumer. The producer creates the `Future` and is responsible for completing or
|
||||||
|
failing it while the caller waits for completion and may `cancel` it.
|
||||||
|
|
||||||
|
Although it is technically possible, callers must not `complete` or `fail`
|
||||||
|
futures and callees or other intermediate observers must not `cancel` them as
|
||||||
|
this may lead to panics and shutdown (ie if the future is completed twice or a
|
||||||
|
cancalletion is not handled by the original caller).
|
||||||
|
|
||||||
|
### `noCancel`
|
||||||
|
|
||||||
|
Certain operations must not be cancelled for semantic reasons. Common scenarios
|
||||||
|
include `closeWait` that releases a resources irrevocably and composed
|
||||||
|
operations whose individual steps should be performed together or not at all.
|
||||||
|
|
||||||
|
In such cases, the `noCancel` modifier to `await` can be used to temporarily
|
||||||
|
disable cancellation propagation, allowing the operation to complete even if
|
||||||
|
the caller initiates a cancellation request:
|
||||||
|
|
||||||
|
```nim
|
||||||
|
proc deepSleep(dur: Duration) {.async.} =
|
||||||
|
# `noCancel` prevents any cancellation request by the caller of `deepSleep`
|
||||||
|
# from reaching `sleepAsync` - even if `deepSleep` is cancelled, its future
|
||||||
|
# will not complete until the sleep finishes.
|
||||||
|
await noCancel sleepAsync(dur)
|
||||||
|
|
||||||
|
let future = deepSleep(10.minutes)
|
||||||
|
|
||||||
|
# This will take ~10 minutes even if we try to cancel the call to `deepSleep`!
|
||||||
|
await cancelAndWait(future)
|
||||||
|
```
|
||||||
|
|
||||||
|
### `join`
|
||||||
|
|
||||||
|
The `join` modifier to `await` allows cancelling an `async` procedure without
|
||||||
|
propagating the cancellation to the awaited operation. This is useful when
|
||||||
|
`await`:ing a `Future` for monitoring purposes, ie when a procedure is not the
|
||||||
|
owner of the future that's being `await`:ed.
|
||||||
|
|
||||||
|
One situation where this happens is when implementing the "observer" pattern,
|
||||||
|
where a helper monitors an operation it did not initiate:
|
||||||
|
|
||||||
|
```nim
|
||||||
|
var tick: Future[void]
|
||||||
|
proc ticker() {.async.} =
|
||||||
|
while true:
|
||||||
|
tick = sleepAsync(1.second)
|
||||||
|
await tick
|
||||||
|
echo "tick!"
|
||||||
|
|
||||||
|
proc tocker() {.async.} =
|
||||||
|
# This operation does not own or implement the operation behind `tick`,
|
||||||
|
# so it should not cancel it when `tocker` is cancelled
|
||||||
|
await join tick
|
||||||
|
echo "tock!"
|
||||||
|
|
||||||
|
let
|
||||||
|
fut = ticker() # `ticker` is now looping and most likely waiting for `tick`
|
||||||
|
fut2 = tocker() # both `ticker` and `tocker` are waiting for `tick`
|
||||||
|
|
||||||
|
# We don't want `tocker` to cancel a future that was created in `ticker`
|
||||||
|
waitFor fut2.cancelAndWait()
|
||||||
|
|
||||||
|
waitFor fut # keeps printing `tick!` every second.
|
||||||
|
```
|
||||||
|
|
||||||
## Compile-time configuration
|
## Compile-time configuration
|
||||||
|
|
||||||
`chronos` contains several compile-time [configuration options](./chronos/config.nim) enabling stricter compile-time checks and debugging helpers whose runtime cost may be significant.
|
`chronos` contains several compile-time
|
||||||
|
[configuration options](./chronos/config.nim) enabling stricter compile-time
|
||||||
|
checks and debugging helpers whose runtime cost may be significant.
|
||||||
|
|
||||||
Strictness options generally will become default in future chronos releases and allow adapting existing code without changing the new version - see the [`config.nim`](./chronos/config.nim) module for more information.
|
Strictness options generally will become default in future chronos releases and
|
||||||
|
allow adapting existing code without changing the new version - see the
|
||||||
|
[`config.nim`](./chronos/config.nim) module for more information.
|
||||||
|
|
Loading…
Reference in New Issue