Concurrencia y multihilo en Rust: seguridad y rendimiento

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course
```html

Concurrencia y multihilo en Rust: escribiendo código seguro y rápido



Los programas modernos rara vez funcionan en modo monohilo. El procesamiento de solicitudes, el trabajo con archivos, las operaciones de red — todo esto requiere la ejecución paralela de tareas. Rust ofrece un enfoque único para la concurrencia: garantiza la seguridad de memoria en tiempo de compilación, previniendo las condiciones de carrera. En este artículo analizaremos cómo trabajar con hilos, canales, mutex y asincronía en Rust.



1. Fundamentos del multihilo: creación y gestión de hilos



En Rust, los hilos se crean a través de la biblioteca estándar std::thread. Cada hilo se ejecuta de forma independiente, pero el compilador supervisa estrictamente el tiempo de vida de las variables.



Creación de un hilo

use std::thread;use std::time::Duration;

fn main() { let handle = thread::spawn(|| { for i in 1..10 { println!("Hilo: {}", i); thread::sleep(Duration::from_millis(100)); } });

for i in 1..5 { println!("Hilo principal: {}", i); thread::sleep(Duration::from_millis(100)); }

handle.join().unwrap(); // Esperamos a que el hilo termine}


Captura de propiedad en closures

Si el hilo utiliza variables del ámbito externo, es necesario transferir la propiedad mediante move:

let data = vec![1, 2, 3];

let handle = thread::spawn(move || { println!("Datos: {:?}", data);});

handle.join().unwrap();// println!("{:?}", data); // ¡Error! data fue movida


2. Intercambio de datos: mutex y bloqueos



Para el acceso seguro a datos compartidos desde múltiples hilos, Rust utiliza Mutex (mutex) en combinación con Arc (contador de referencias atómico).



Ejemplo con Mutex y Arc

use std::sync::{Arc, Mutex};use std::thread;

fn main() { let counter = Arc::new(Mutex::new(0)); let mut handles = vec![];

for _ in 0..10 { let counter = Arc::clone(&counter); let handle = thread::spawn(move || { let mut num = counter.lock().unwrap(); *num += 1; }); handles.push(handle); }

for handle in handles { handle.join().unwrap(); }

println!("Resultado: {}", *counter.lock().unwrap()); // 10}


Importante: Mutex se desbloquea automáticamente al salir del ámbito de visibilidad. Esto previene el deadlock (bloqueo mutuo) a nivel de compilación.



RwLock — para lecturas frecuentes

Si los datos raramente se modifican pero se leen con frecuencia, use RwLock:

use std::sync::RwLock;

let lock = RwLock::new(5);

{ let r1 = lock.read().unwrap(); let r2 = lock.read().unwrap(); // Se puede leer simultáneamente println!("{} {}", r1, r2);}

{ let mut w = lock.write().unwrap(); *w += 1; // La escritura bloquea la lectura}


3. Canales: transmisión de mensajes entre hilos



Rust soporta el modelo de actores a través de canales (std::sync::mpsc). Esto permite que los hilos intercambien datos sin memoria compartida.



Ejemplo con canal

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

fn main() { let (tx, rx) = mpsc::channel();

thread::spawn(move || { let vals = vec!["hello", "from", "the", "thread"]; for val in vals { tx.send(val).unwrap(); thread::sleep(std::time::Duration::from_secs(1)); } });

for received in rx { println!("Recibido: {}", received); }}


Múltiples remitentes

Con mpsc::Sender se puede clonar el remitente para varios hilos:

let (tx, rx) = mpsc::channel();let tx1 = tx.clone();

thread::spawn(move || { tx1.send("Hilo 1").unwrap(); });thread::spawn(move || { tx.send("```

Blogs

Book Recommendations