4 ms·
I write (async) Rust regularly, and I don't understand how the version in the appendix doesn't take 10x1,000,000 seconds to complete. In other words, I'd have e
by davidatbu 2y ago
I write (async) Rust regularly, and I don't understand how the version in the appendix doesn't take 10x1,000,000 seconds to complete. In other words, I'd have expected no concurrency to take place.
Am I wrong?
UPDATE: From the replies below, it looks like I was right about "no concurrency takes place", but I was wrong about how long it takes, because `tokio::time::sleep()` keeps track of when the future was created, (ie when `sleep()` was called) instead of when the future is first `.await`ed (which was my unsaid assumption).
- sour-taste 2y agoTokyo::sleep is async
- davidatbu 2y agoI think the points people made in other replies make sense, but "Tokio::sleep is async" by itself is not enough of an explanation. If it were the case that `Tokio::sleep()` tracked the moment `.await` was called as it's start time, I believe it would indeed take 10x1,000,000 seconds, _even if it's async_.
- claytonwramsey 2y agoThe implementation of `sleep` [1] decides the wake up time by when `sleep` is called, rather than when its future is polled. So the first task waits one second, then the remaining tasks see that they have already passed the wake-up time and so return instantly. [1]: https://docs.rs/tokio/latest/tokio/time/fn.sleep.html https://docs.rs/tokio/latest/tokio/time/fn.sleep.html
- davidatbu 2y agoThis makes total sense!
- fuzzybear3965 2y agoYeah, I think you're wrong. It should only take ~10s. tokio::time::sleep records the time it was called before returning the future [1]. So, all 1 million tasks should be stamped with +/- the same time (within a few milliseconds). [1]: https://docs.rs/tokio/1.41.1/src/tokio/time/sleep.rs.html#128-131 https://docs.rs/tokio/1.41.1/src/tokio/time/sleep.rs.html#12...
- davidatbu 2y agoThis makes total sense!
- vbsd 2y ago> because `tokio::time::sleep()` keeps track of when the future was created, (ie when `sleep()` was called) instead of when the future is first `.await`ed I’m not a Rust programmer but I strongly suspect this updated explanation is erroneous. It’s probably more like this: start time is recorded when the task execution is started. However, the task immediately yields control back to the async loop. Then the async loop starts another task, and so on. It’s just that the async loop only returns the control to sleeping task no earlier than the moment 1s passes after the task execution was initialy started. I’d be surprised if it had anything to do with when sleep() was called.
- davidatbu 2y agoSomeone linked the code in another comment, and the start time is most definitely recorded when the future is created: https://docs.rs/tokio/1.41.1/src/tokio/time/sleep.rs.html#128-131 https://docs.rs/tokio/1.41.1/src/tokio/time/sleep.rs.html#12...
- vbsd 2y agoHuh, you're right about this, thanks. On the other hand, I maintain that this is an incidental rather than essential reason for the program finishing quickly. In that benchmark code, we can replace "sleep" with our custom sleep function which does not record start time before execution: async fn wrapped_sleep(d: Duration) { sleep(d).await } The following program will still finish in ~10 seconds. #[tokio::main] async fn main() { let num_tasks = 100; let mut tasks = Vec::new(); for _ in 0..num_tasks { tasks.push(wrapped_sleep(Duration::from_secs(10))); } futures::future::join_all(tasks).await; }
- davidatbu 2y agoIn `wrapped_sleep` function body, where does the `sleep()` come from? It's still tokio::time::sleep, right? If so, the start time is recorded before the first `.await`. Regardless, the program you provided _does_ actually run the futures concurrently, because of the `join_all()`. My point above was that in the original blog post, the appendix has a version without `join_all()`, which has no concurrency.