0Pricing
Learn Rust Coding · Aula

Trabalho com Futuros e Tarefas

Compreenda a trait `Future` e como as tarefas são agendadas e geridas num ambiente de execução assíncrono.

Trabalho com Futuros e Tarefas é uma aula grátis de Learn Rust Coding no CoddyKit. Esta é a aula 3 de 3. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Learn Rust Coding, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Learn Rust Coding inclui 3 aulas no total.

Partes desta aula ainda não foram traduzidas e aparecem em inglês.

What is a Rust Future?

In asynchronous Rust, a Future is a trait that represents an asynchronous computation which may complete at some point. Think of it as a promise for a value that isn't ready yet.

  • It's the core building block for async Rust.
  • async fns in Rust actually return an anonymous type that implements the Future trait.
  • The value isn't computed immediately; it's computed when the Future is "polled" by an executor.

How Futures Make Progress

A Future doesn't run on its own. An executor (like the Tokio runtime) repeatedly "polls" it to check if it has made progress or completed.

  • When polled, a Future returns either Poll::Pending (not done yet) or Poll::Ready(T) (done, here's the result).
  • If Pending, the executor knows to poll it again later when something relevant happens (e.g., I/O finishes).
  • This polling mechanism is what allows many asynchronous operations to run concurrently on a single thread.

Your async Code is a Future

When you write an async fn, Rust transforms it into a state machine that implements the Future trait. The actual computation only starts when the returned Future is polled.

Let's see a simple async function. It doesn't run until awaited by an executor.

async fn say_hello() -> String {
    "Hello from a Future!".to_string()
}

#[tokio::main]
async fn main() {
    let future = say_hello(); // This doesn't run the function yet!
    println!("Future created, but not awaited.");
    // To run it, an executor needs to poll it, often via .await
    // let result = future.await;
    // println!("{}", result);
}

Futures Become Tasks

While a Future is the definition of an async computation, a task is an active instance of that Future being driven to completion by an executor.

  • When you tell an executor (like Tokio) to run a Future, it wraps it in a task.
  • The executor then manages this task, polling it whenever it's ready to make progress.
  • Tasks are the units of work that the async runtime schedules and executes concurrently.

Spawning Tasks for Concurrency

To run a Future concurrently with other code, you "spawn" it onto the Tokio runtime. This creates a new task that the runtime will manage.

The tokio::spawn function takes a Future and returns a JoinHandle, which you can use to await the task's completion and get its result.

async fn perform_task(id: u8) -> String {
    tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
    format!("Task {} finished!", id)
}

#[tokio::main]
async fn main() {
    println!("Main started.");
    let handle = tokio::spawn(async {
        perform_task(1).await
    });
    println!("Task 1 spawned.");
    // We will await 'handle' in the next scene to get the result.
    // let result = handle.await.unwrap();
    // println!("{}", result);
}

Getting Results from Tasks

The JoinHandle returned by tokio::spawn is itself a Future. You can .await this handle to wait for the spawned task to complete and retrieve its return value.

If the spawned task panics, awaiting its JoinHandle will return an error.

async fn perform_task(id: u8) -> String {
    tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
    format!("Task {} finished!", id)
}

#[tokio::main]
async fn main() {
    println!("Main started.");
    let handle = tokio::spawn(async {
        perform_task(1).await
    });
    println!("Task 1 spawned.");
    let result = handle.await.unwrap(); // Await the handle to get the result
    println!("{}", result);
    println!("Main finished.");
}

Multiple Concurrent Tasks

The power of tasks and tokio::spawn truly shines when you run multiple operations concurrently. The Tokio runtime efficiently switches between tasks as they become ready.

This allows your program to make progress on many things at once without blocking, even on a single thread.

async fn long_task(id: u8) -> String {
    tokio::time::sleep(tokio::time::Duration::from_millis(100 + id as u64 * 50)).await;
    format!("Long task {} done!", id)
}

#[tokio::main]
async fn main() {
    println!("Main started.");
    let handle1 = tokio::spawn(long_task(1));
    let handle2 = tokio::spawn(long_task(2));
    println!("Both tasks spawned.");
    let result1 = handle1.await.unwrap();
    let result2 = handle2.await.unwrap();
    println!("{}\n{}", result1, result2);
    println!("Main finished.");
}

Waiting for All with join!

When you need to wait for several Futures to complete at the same time, tokio::join! is a useful macro. It waits for all given futures concurrently and returns their results as a tuple.

It's similar to awaiting each handle individually, but often more concise for fixed numbers of futures.

async fn fetch_data(source: &str) -> String {
    tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
    format!("Data from {}", source)
}

#[tokio::main]
async fn main() {
    println!("Starting data fetches...");
    let (data_a, data_b) = tokio::join!(
        fetch_data("Server A"),
        fetch_data("Database B")
    );
    println!("Fetched: {}\nFetched: {}", data_a, data_b);
    println!("All fetches complete.");
}

Handling Task Errors

Asynchronous operations can fail, just like synchronous ones. It's common for Futures to return a Result type, indicating success or failure.

When awaiting a JoinHandle, remember that the result is wrapped in another Result because the task itself might panic. You'll often see handle.await? (if in an async fn returning Result) or handle.await.unwrap() / .expect().

async fn might_fail(should_fail: bool) -> Result<String, &'static str> {
    tokio::time::sleep(tokio::time::Duration::from_millis(30)).await;
    if should_fail {
        Err("Oops, something went wrong!")
    } else {
        Ok("Operation successful!".to_string())
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let handle_ok = tokio::spawn(might_fail(false));
    let handle_err = tokio::spawn(might_fail(true));

    let result_ok = handle_ok.await??; // Await handle, then await inner Result
    println!("{}", result_ok);

    match handle_err.await? { // Await handle, then handle inner Result
        Ok(val) => println!("{}", val),
        Err(e) => eprintln!("Error: {}", e),
    }
    Ok(())
}

Understanding Futures & Tasks

You've learned about Futures as computations and Tasks as their execution instances. Which statement about tokio::spawn and JoinHandle is true?

Recap: Futures and Tasks

Great job! You've now grasped the core concepts of Futures and tasks in Rust's asynchronous ecosystem:

  • A Future is a trait representing an asynchronous computation that will eventually produce a value.
  • async fns compile down to types that implement the Future trait.
  • A task is an instance of a Future that an executor (like Tokio) actively manages and polls.
  • tokio::spawn is used to create a new task, returning a JoinHandle.
  • You .await a JoinHandle to get the result of a spawned task.

These building blocks are essential for writing efficient, non-blocking Rust applications!

Perguntas Frequentes

A aula “Trabalho com Futuros e Tarefas” é grátis?

Sim — o texto completo de “Trabalho com Futuros e Tarefas” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Learn Rust Coding, atualize para CoddyKit PRO. O curso de Learn Rust Coding inclui 3 aulas no total.

O que vou aprender em “Trabalho com Futuros e Tarefas”?

Compreenda a trait `Future` e como as tarefas são agendadas e geridas num ambiente de execução assíncrono. Você pratica Learn Rust Coding com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Learn Rust Coding?

Nenhuma experiência prévia é necessária. Learn Rust Coding no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 3.

Quanto tempo leva a aula “Trabalho com Futuros e Tarefas”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Learn Rust Coding?

Sim. Cada aula de Learn Rust Coding inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Introdução a Async/Await
  2. Criação de Aplicações Assíncronas com Tokio
  3. Trabalho com Futuros e Tarefas
← Voltar para Learn Rust Coding