I added numbers to the above post to make it easier to call out, and created GitHub - joshka/spike-tokio
I Added a loop counter (either AtomicUsize or Arc<AtomicUsize>) to each example to show what’s going on a bit better. You’ll note that there’s two broadly similar counts, ~70 where the loop is waiting 20ms between iterations, and ~6300 where it is printing characters to the terminal as fast as possible. The amount of time spent is similar because this is controlled by the time it takes to run the fibonacci method (I’m using 42 for the number).
1 Fibonacci number: 267914296, loop_count: 6431
cargo run --bin item1 3.82s user 0.09s system 164% cpu 2.374 total
2 Fibonacci number: 267914296, loop_count: 73
cargo run --bin item2 1.82s user 0.02s system 92% cpu 1.977 total
3 Fibonacci number: 267914296, loop_count: 6385
cargo run --bin item3 3.84s user 0.10s system 167% cpu 2.355 total
4 Fibonacci number: 267914296, loop_count: 74
cargo run --bin item4 1.82s user 0.02s system 92% cpu 1.999 total
5 Fibonacci number: 267914296, loop_count: 73
cargo run --bin item5 1.82s user 0.02s system 93% cpu 1.975 total
I’m not sure what’s not understandable about this one. It spawns a task, which starts running while fib is running on the main thread.
6 Never returns
Spawned tasks may be cancelled using the
JoinHandle::abortorAbortHandle::abortmethods. When one of these methods are called, the task is signalled to shut down next time it yields at an.awaitpoint. If the task is already idle, then it will be shut down as soon as possible without running again before being shut down. Additionally, shutting down a Tokio runtime (e.g. by returning from#[tokio::main]) immediately cancels all tasks on it...
Be aware that calls to
JoinHandle::abortjust schedule the task for cancellation, and will return before the cancellation has completed. To wait for cancellation to complete, wait for the task to finish by awaiting theJoinHandle. Similarly, theJoinHandle::is_finishedmethod does not returntrueuntil the cancellation has finished.
There’s no await point in the loop, so it never gets interrupted. Add yield_now().await; and it does. Also calling std::process::exit(1) makes things die.
Also, anything that runs in the code after that point runs at the same time as the async task, so if for instance you’re printing the result of fib, then it will be interspersed with the random junk, so it’s important to await the handle.
So adding:
yield_now().await;
}
});
let result = fib(NUMBER);
handle.abort();
if let Err(err) = handle.await {
eprintln!("Error: {:?}", err);
}
gives:
Error: JoinError::Cancelled(Id(13))
Fibonacci number: 267914296, loop_count: 6305
cargo run --bin item6 3.88s user 0.14s system 154% cpu 2.609 total
7 Never completes
But it does run any code after the abort (e.g. printing the result / loop count. The problem here is also mentioned at tokio::task - Rust
Be aware that tasks spawned using
spawn_blockingcannot be aborted because they are not async. If you callaborton aspawn_blockingtask, then this will not have any effect, and the task will continue running normally. The exception is if the task has not started running yet; in that case, callingabortmay prevent the task from starting.
To get this one to succeed, you’d want to add some form of cancelation token / message that the loop can check.
let (tx, mut rx) = tokio::sync::oneshot::channel::<()>();
// then in the loop
if rx.try_recv().is_ok() {
break;
}
// and after
tx.send(()).unwrap();
Fibonacci number: 267914296, loop_count: 77
cargo run --bin item7 1.84s user 0.02s system 59% cpu 3.150 total
8 never completes
same deal as 7. blocking task can’t be aborted
Applying the same change
Fibonacci number: 267914296, loop_count: 6448
cargo run --bin item8 3.84s user 0.10s system 156% cpu 2.526 total
I suspect given this note about canceling, you’d probably get the same effect to calling abort as just letting the method end.
Additionally, shutting down a Tokio runtime (e.g. by returning from
#[tokio::main]) immediately cancels all tasks on it.
See fix: make things work right · joshka/spike-tokio@18e6c4f · GitHub for corrections