yieldAsync() (#120)
This commit is contained in:
parent
d0a17d551f
commit
284d677815
47
README.md
47
README.md
|
@ -242,6 +242,53 @@ other specific exception, in order to avoid catching by mistake
|
|||
`CancelledError` (object of `Exception`, used internally to propagate
|
||||
cancellation).
|
||||
|
||||
### Yielding
|
||||
|
||||
If you need to give control back to the event loop, but there's no future you
|
||||
need to `await` at that point, you can call `yieldAsync()` - a simple wrapper
|
||||
around `sleepAsync()`:
|
||||
|
||||
```nim
|
||||
template yieldAsync*() =
|
||||
await sleepAsync(0.seconds)
|
||||
```
|
||||
|
||||
This comes in handy when splitting a blocking task into smaller parts:
|
||||
|
||||
```nim
|
||||
proc showMsg(after: int) {.async.} =
|
||||
echo "begin showMsg()"
|
||||
await sleepAsync(after.seconds)
|
||||
echo "msg: after = ", after
|
||||
|
||||
let maxDuration = 10
|
||||
|
||||
proc heavy() {.async.} =
|
||||
echo "begin showMsg(", after, ")"
|
||||
let start = Moment.now()
|
||||
var s: uint64
|
||||
while true:
|
||||
s += 1
|
||||
|
||||
# try commenting this out and see what happens
|
||||
if s mod 1000000 == 0:
|
||||
yieldAsync()
|
||||
|
||||
if (Moment.now() - start).seconds >= (maxDuration + 1):
|
||||
break
|
||||
echo "sum: ", s
|
||||
|
||||
proc p1() {.async.} =
|
||||
var futures: seq[Future[void]]
|
||||
|
||||
for after in 1..maxDuration:
|
||||
futures.add(showMsg(after))
|
||||
futures.add(heavy())
|
||||
await allFutures(futures)
|
||||
|
||||
waitFor p1()
|
||||
```
|
||||
|
||||
## TODO
|
||||
* Pipe/Subprocess Transports.
|
||||
* Multithreading Stream/Datagram servers
|
||||
|
|
|
@ -891,6 +891,10 @@ proc sleepAsync*(ms: int): Future[void] {.
|
|||
inline, deprecated: "Use sleepAsync(Duration)".} =
|
||||
result = sleepAsync(ms.milliseconds())
|
||||
|
||||
# This can't be an async proc, because its `await` needs to modify the caller.
|
||||
template yieldAsync*() =
|
||||
await sleepAsync(0.seconds)
|
||||
|
||||
proc withTimeout*[T](fut: Future[T], timeout: Duration): Future[bool] =
|
||||
## Returns a future which will complete once ``fut`` completes or after
|
||||
## ``timeout`` milliseconds has elapsed.
|
||||
|
|
|
@ -969,6 +969,38 @@ suite "Future[T] behavior test suite":
|
|||
proc testCancellationRace(): bool =
|
||||
waitFor(testCancellationRaceAsync())
|
||||
|
||||
proc testYieldAsync(): Future[bool] {.async.} =
|
||||
proc showMsg(after: int, results: ptr seq[string]) {.async.} =
|
||||
await sleepAsync(after.seconds)
|
||||
results[].add("after " & $after)
|
||||
|
||||
let maxDuration = 2
|
||||
|
||||
proc heavy(results: ptr seq[string]) {.async.} =
|
||||
let start = Moment.now()
|
||||
var s: uint64
|
||||
while true:
|
||||
s += 1
|
||||
if s mod 1000000 == 0:
|
||||
yieldAsync()
|
||||
if (Moment.now() - start).seconds >= (maxDuration + 1):
|
||||
break
|
||||
results[].add("heavy")
|
||||
|
||||
var
|
||||
futures: seq[Future[void]]
|
||||
results: seq[string]
|
||||
|
||||
for after in 1..maxDuration:
|
||||
futures.add(showMsg(after, results.addr))
|
||||
futures.add(heavy(results.addr))
|
||||
await allFutures(futures)
|
||||
|
||||
return results == @["after 1", "after 2", "heavy"]
|
||||
|
||||
proc testYield(): bool =
|
||||
waitFor(testYieldAsync())
|
||||
|
||||
test "Async undefined behavior (#7758) test":
|
||||
check test1() == true
|
||||
test "Immediately completed asynchronous procedure test":
|
||||
|
@ -1022,3 +1054,6 @@ suite "Future[T] behavior test suite":
|
|||
check testWithTimeout() == true
|
||||
test "Cancellation race test":
|
||||
check testCancellationRace() == true
|
||||
test "Yielding test":
|
||||
check testYield() == true
|
||||
|
||||
|
|
Loading…
Reference in New Issue