Asynchronous Programming in Rust: A Complete Guide for Beginners

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Asynchronous Programming in Rust: A Complete Guide for Beginners

\n\n

Asynchronous programming is a paradigm that allows you to execute multiple tasks simultaneously without blocking the main execution thread. In Rust, asynchrony is implemented through the async and .await keywords, as well as through a powerful runtime such as Tokio. This guide will help you understand the basics of asynchronous programming in Rust, even if you are just starting your journey.

\n\n

What is asynchronous programming and why is it needed?

\n\n

In traditional synchronous code, each operation is executed sequentially. If a program makes an HTTP request, it waits for a response, doing nothing. In an asynchronous approach, the program can initiate a request and switch to another task while waiting for a response. This is especially important for:

\n\n
    \n
  • Network applications — web servers, API clients, chats.
  • \n
  • Working with files — reading/writing large amounts of data.
  • \n
  • User interfaces — so the interface does not "freeze" during background operations.
  • \n
\n\n

Rust offers zero-cost abstractions: asynchronous code compiles into efficient machine instructions. Unlike other languages where asynchrony can be "overhead," Rust allows you to write fast and safe asynchronous programs.

\n\n

Basics of async/await in Rust

\n\n

The async and .await keywords are the foundation of asynchronous programming in Rust. Let's break them down with a simple example.

\n\n

1. Creating an async function

\n\n

Any function can become asynchronous by adding the async keyword before it. Such a function returns a Future — a value that is not yet ready but will be ready in the future.

\n\n
// Synchronous function\nfn say_hello_sync() -> String {\n    String::from("Hello, World!")\n}\n\n// Asynchronous function\nasync fn say_hello_async() -> String {\n    String::from("Hello, World!")\n}
\n\n

Note: if you simply call say_hello_async(), the code will not execute. You will get a Future object that needs to be "run" using a runtime.

\n\n

2. Awaiting the result with .await

\n\n

To get the value from a Future, use .await. This keyword tells the compiler: "pause the execution of this function until the Future is ready, and let other tasks work."

\n\n
async fn process() {\n    let result = say_hello_async().await;\n    println!("{}", result);\n}
\n\n

3. Async blocks

\n\n

You can also create asynchronous blocks of code "on the fly":

\n\n
let future = async {\n    let x = 10;\n    let y = 20;\n    x + y\n};\n\nlet result = future.await; // result: 30
\n\n

Runtime: Tokio — the heart of async Rust

\n\n

By themselves, async and .await do not run code. You need a runtime — an execution environment that manages tasks and the scheduler. The most popular library for this is Tokio.

\n\n

Installing Tokio

\n\n

Add to Cargo.toml:

\n\n
[dependencies]\ntokio = { version = "1.0", features = ["full"] }
\n\n

First async project

\n\n

To run asynchronous code, use the #[tokio::main] macro. It automatically creates a runtime and runs your function.

\n\n
use tokio;\n\n#[tokio::main]\nasync fn main() {\n    println!("Running async code!");\n    let result = say_hello_async().await;\n    println!("Result: {}", result);\n}\n\nasync fn say_hello_async() -> String {\n    // Simulating a long operation\n    tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;\n    String::from("Hello, Async Wo                

Blogs

Book Recommendations