0Pricing
Learn Rust Coding · Lección

Canales mpsc

Enviar entre hilos

Canales mpsc es una lección gratuita de Learn Rust Coding en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Learn Rust Coding, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Learn Rust Coding incluye 4 lecciones en total.

Partes de esta lección aún no han sido traducidas y se muestran en inglés.

What Is a Channel?

A channel is a one-way pipe for sending values from one thread to another. Rust's standard library provides std::sync::mpsc where mpsc means multiple producer, single consumer.

  • The Sender half pushes values in.
  • The Receiver half pulls values out.

Channels let threads communicate by passing messages instead of sharing memory directly, which avoids many data races.

Creating a Channel

Call mpsc::channel() to get a tuple of (Sender, Receiver). Here we send one value from a spawned thread back to the main thread.

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    thread::spawn(move || {
        tx.send(42).unwrap();
    });
    let received = rx.recv().unwrap();
    println!("Got: {}", received);
}

send and recv

tx.send(value) returns a Result: it fails only if the receiver has been dropped. rx.recv() blocks until a value arrives, returning Err when all senders are gone.

  • send moves ownership of the value into the channel.
  • recv takes ownership out on the other side.
use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    thread::spawn(move || {
        let msg = String::from("hello from thread");
        tx.send(msg).unwrap();
    });
    let text = rx.recv().unwrap();
    println!("{}", text);
}

Ownership Moves Through the Channel

Because send takes the value by value, you cannot use it after sending. This compile-time rule guarantees no thread keeps a stale reference to data now owned by another thread.

Below, trying to print msg after send would be a compile error, so we only use it once.

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    thread::spawn(move || {
        let data = vec![1, 2, 3];
        tx.send(data).unwrap();
        // data is moved; cannot use it here
    });
    let v = rx.recv().unwrap();
    println!("Sum: {}", v.iter().sum::<i32>());
}

Iterating Over a Receiver

A Receiver implements IntoIterator. Looping over it yields each value until the channel closes (all senders dropped). This is the idiomatic way to consume a stream of messages.

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    thread::spawn(move || {
        for i in 1..=3 {
            tx.send(i).unwrap();
        }
    });
    for received in rx {
        println!("Received: {}", received);
    }
}

Multiple Producers with clone

The mp in mpsc means you can have many senders. Clone the Sender and give a copy to each thread. The receiver collects everything until every clone is dropped.

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    let tx2 = tx.clone();
    thread::spawn(move || { tx.send("from A").unwrap(); });
    thread::spawn(move || { tx2.send("from B").unwrap(); });
    for msg in rx {
        println!("{}", msg);
    }
}

Channel Closing Semantics

The receiver loop ends automatically when all senders are dropped. If even one Sender stays alive, for msg in rx blocks forever waiting for more. Always drop or scope senders correctly to let the loop finish.

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    let handle = thread::spawn(move || {
        for i in 0..3 {
            tx.send(i * 10).unwrap();
        }
        // tx dropped here, closing the channel
    });
    handle.join().unwrap();
    let total: i32 = rx.iter().sum();
    println!("Total: {}", total);
}

try_recv for Non-Blocking Reads

recv blocks, but try_recv returns immediately with a Result. It gives Ok(value) if a message is ready, or Err if the channel is empty or disconnected. Useful in event loops that must keep doing other work.

use std::sync::mpsc;
use std::thread;
use std::time::Duration;

fn main() {
    let (tx, rx) = mpsc::channel();
    thread::spawn(move || {
        thread::sleep(Duration::from_millis(50));
        tx.send("ready").unwrap();
    });
    loop {
        match rx.try_recv() {
            Ok(msg) => { println!("{}", msg); break; }
            Err(_) => println!("waiting..."),
        }
        thread::sleep(Duration::from_millis(20));
    }
}

Sending Custom Types

Any type that is Send can travel through a channel, including your own structs and enums. Enums are great for modeling distinct message kinds in a worker protocol.

use std::sync::mpsc;
use std::thread;

enum Job {
    Print(String),
    Add(i32, i32),
}

fn main() {
    let (tx, rx) = mpsc::channel();
    thread::spawn(move || {
        tx.send(Job::Print(String::from("hi"))).unwrap();
        tx.send(Job::Add(2, 3)).unwrap();
    });
    for job in rx {
        match job {
            Job::Print(s) => println!("print: {}", s),
            Job::Add(a, b) => println!("add: {}", a + b),
        }
    }
}

sync_channel and Backpressure

mpsc::sync_channel(n) creates a bounded channel with buffer size n. When the buffer is full, send blocks until space frees up. This gives you backpressure, preventing a fast producer from overwhelming a slow consumer.

  • sync_channel(0) is a rendezvous channel: send and recv must meet.
use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::sync_channel(2);
    thread::spawn(move || {
        for i in 1..=4 {
            tx.send(i).unwrap();
            println!("sent {}", i);
        }
    });
    for v in rx {
        println!("got {}", v);
    }
}

A Simple Worker Pattern

Channels shine for the producer/consumer pattern: one thread produces work items, another consumes and processes them. Here the main thread produces numbers and a worker squares each one and reports back over a second channel.

use std::sync::mpsc;
use std::thread;

fn main() {
    let (job_tx, job_rx) = mpsc::channel();
    let (res_tx, res_rx) = mpsc::channel();
    thread::spawn(move || {
        for n in job_rx {
            res_tx.send(n * n).unwrap();
        }
    });
    for n in 1..=4 {
        job_tx.send(n).unwrap();
    }
    drop(job_tx);
    for r in res_rx {
        println!("square: {}", r);
    }
}

Quick Check

Test your understanding of mpsc channels.

Recap

You learned the core of mpsc channels:

  • mpsc::channel() returns a (Sender, Receiver) pair.
  • send moves a value in; recv blocks to take it out.
  • Iterating a receiver consumes messages until all senders drop.
  • Clone the Sender for multiple producers.
  • try_recv is non-blocking; sync_channel(n) adds bounded backpressure.

Channels let threads share data safely by passing ownership rather than sharing memory.

Preguntas frecuentes

¿La lección «Canales mpsc» es gratis?

Sí — el texto completo de «Canales mpsc» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Learn Rust Coding, actualiza a CoddyKit PRO. El curso de Learn Rust Coding incluye 4 lecciones en total.

¿Qué aprenderé en «Canales mpsc»?

Enviar entre hilos Practicas Learn Rust Coding con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Learn Rust Coding?

No se requiere experiencia previa. Learn Rust Coding en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.

¿Cuánto tiempo toma la lección «Canales mpsc»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Learn Rust Coding?

Sí. Cada lección de Learn Rust Coding incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Canales mpsc
  2. Compartir estado con Arc/Mutex
  3. Hilos con ámbito
  4. Canales Crossbeam
← Volver a Learn Rust Coding