About mulitasking

After some googling, I've arrived at this thread, Difference between await & block_on() and found the following statements:

This is not the same, is it? So what is more right, or perhaps more clearly expressed?

It seems to me that both are correct, although the "it can't be called in an async context" can be made a bit more precise as "async code should usually not do anything that blocks, and calling block_on will block, so this is bad". So its not that you can't, it's more that it's usually incorrect to do so.

In this blog post on blocking it is explained what "blocking" is, and that an .await allows your asynchronous runtime to swap the currently running task for something else. (Which block_on doesn't do.)

5 Likes

I guess these are two sides of the same coin:

  • block_on() "goes to an async context" in the sense that it lets you usefully call into async code from non-concurrent code;
  • but it also "goes to blocking context" in the sense that if you've got a future and you call block_on() on it, you now have a piece of blocking code.

These are exactly the same thing, viewed differently.

3 Likes

Assume that I have a timer that ticks once every second, and after each tick, a time-consuming activity is started. If this activity uses block_on, will this stop the timer until the activity is through, or will the timer continue ticking and starting new activities with block_on?

Does it depend on which runtime I'm using?

Does adding tokio to dependencies imply that I'm using the tokio runtime, or is there another factor?

You can't test it on Playground, and I have no access to my IDE right now.

I posted a comment on H2CO3's reply, but it also concerns your replay.

When something blocks the thread, it only blocks things on the same thread. The system clock is generally controlled by the OS rather than your program, so it is usually not blocked by this kind of thing.

To use Tokio, you have to actually create a Tokio runtime and start it. There are several ways to do that:

  • Put #[tokio::main] on your main function.
  • Call block_on on an async function.
  • Call spawn on an async function.
1 Like

I've tested this case using this code:

  tokio::spawn( async {
      let tick = schedule_recv::periodic_ms(1000);
      loop {
          tick.recv().unwrap();
          let now = Local::now().format("%H:%M:%S").to_string();
          println!("loop:       {}", now);
          block_on( task() );     // task() takes 10s to complete
      }
  });

block_on stops the thread totally. The timer printout appears every 10 seconds, so you can say that block_on also stops the timer on this thread. Obviously, the OS can schedule numerous other activities during the lengthy execution of task(), but that is why we have OS.

I mean, obviously if you don't go back to look at the timer until after it should have triggered then it wont trigger when it should. However, this is not really a problem cause by block_on. This would have the same problem:

  tokio::spawn( async {
      let tick = schedule_recv::periodic_ms(1000);
      loop {
          tick.recv().unwrap();
          let now = Local::now().format("%H:%M:%S").to_string();
          println!("loop:       {}", now);
          task().await;     // task() takes 10s to complete
      }
  });

As an aside, this is using a blocking mechanism for sleeping, which is not advised. You should be using tokio::time instead. See my previous link for more.

2 Likes

Thank you, alice and Carbonic Acid for the comments. I think we can close this topic.