What exactly is async?

  1. what exactly is async programming?
  2. what problem "async" solves in rust?
  3. How do you explain async programming to someone who is from thread background.
  4. when to use async and when to use thread.
  5. need suggestion on easy guide (video or any tutorial) to start with async
1 Like

The async book covers some of these questions.

tokio is the most popular async runtime. They have a tutorial and other documentation.

1 Like

In brief, async is for co-operative concurrency. Async tasks can be suspended at .await points, yielding control to other tasks. Typically, operations that need to be awaited are those that take a significant amount of time to complete, e.g. waiting for I/O (reading or writing to a file or a network socket, querying a database, etc.)

This solves the problem of blocking: a function waiting for a file or network packet to be available cannot do anything useful, and if it's the only thing running, it prevents other functions from making progress. You can solve this to some extent by threads, but if you exhaust the physically available number of threads, it's end of story again.

It is thus sometimes said figuratively that threading is for working in parallel, while async is for waiting in parallel.

8 Likes

A good way of thinking about asynchronous code in Rust is that it is a method of pausing functions. An async function is pausable, and each .await line is a "checkpoint" where the function can optionally pause.

let a = async {
    for i in 0..50 {
        println!("A: {}", i);
        sleep(1.0).await; // checkpoint
    }
};

let b = async {
    println!("Starting B");
    other_async_fn().await;
    println!("Ending B");
};

// Start both A and B at the same time
tokio::join!(
    a,
    b,
);

In the above code each time .await is called, the Tokio runner checks whether it should continue running that function or if it should switch to the other function. That is why you'll get some 1 2 3s with the occasional Starting B or Ending B.

From a threading perspective, async programs can run on a single thread but it is implementation specific. For some rules of thumb:

  • Async runners like Tokio are in charge of switching which function is running, not the Kernel for threads.
  • You get to choose when these switches can be made in the form of .await checkpoints.
  • Async is great for IO-bound tasks like web servers, but not as much for high-computational programs and the like

I've always found the tutorial for Trio to be a great introduction to asynchronous programming, though it is for Python and not Rust.

1 Like

You should accept the fact that we are talking highly subjective topics here thus everyone would have their own opinion.

I'll try to answer question in an order in which they made some sense.

#3. That one is easy: async is Windows 1.0 (originally). Threads are Windows NT (and other similar things). So the next question would be:

#3a. Why the hack someone would want to go back in time? The answer to that is also simple: JavaScript guys had no choice and C# started fanning that story because threads on Windows are extremely inefficient.

#3b. How the heck Rust is involved if that's only for JavaScript or Windows? The answer to that is: Rust needed async for marketing purposes and thus they adopted it and, as usual, disguised something entirely different under that name.

#3c. What the hack Rust is hiding behind async buzzword? The answer is simple: coroutines. Pretty normal ones, similar but different from what non-crippled languages had many decades ago.

#1. Then what is an async thingie in Rust? In Rust async function is crippled coroutine which can not freely interact with other couroutines but can be “frozen” and “resumed”. You may imagine is as normal function which uses certain “area” in place of usual stack frame and which can be managed by “async runtime”. Parts between await points are executed sequentially while borrowing stack from runtime-provided thread pool, but at the await point coroutine can be frozen and moved to other thread (or replaced with another async routine, etc).

Now we can finally go to #2. If you recall the history of programming you'll know that Windows 1.0 wasn't the only cooperative OS at the time. The other one was NetWare and it was much more efficient and robust than Windows NT… but only till third-party apps have started to become available. Then performance of NetWare was no longer predictable: it could outperform LAN Manager one minute and would become completely unresponsive the next minute.

So async is Rust allows one to generate lightweight and very efficient concurency… which may become completely atrocious if you would use some heavy blocking routines. This gives you an answer to #4: if you need efficiency and feel Ok with the need to track pieces of synchronous code then async is your thing, if you want predictability then threads are better… sadly you often don't have a choice since libraries decide whether you need async or not.

As for #5… Rust for Rustaceans is pretty good, I'm sure there are other nice books, but I'm not sure if there are good free tutorial.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.