docs for `join` and `noCancel`
This commit is contained in:
parent
aab6e8085e
commit
8166d7d0f1
|
@ -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
|
||||
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 -->
|
||||
|
||||
## 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
|
||||
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
|
||||
of downloading two web pages concurrently shows:
|
||||
|
@ -127,8 +131,84 @@ of downloading two web pages concurrently shows:
|
|||
{{#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
|
||||
|
||||
`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