Una herramienta importante que Rust tiene para lograr la concurrencia de envío de mensajes es el channel, un concepto de programación que contiene la biblioteca estándar de Rust.

Rust pretende ser un lenguaje con muy buen soporte para la concurrencia; y tiene tres partes: ownership & lifetimes, los traits Send y Sync, y Mutex.

Channel


Trabajaremos en un programa que tiene un hilo para generar valores y enviarlos por un canal, y otro hilo que recibirá los valores y los imprimirá. Enviaremos valores simples entre hilos usando un canal para ilustrar la función.

use std::sync::mpsc; use std::thread; use std::time::Duration; fn main() { let (tx, rx) = mpsc::channel(); let tx1 = mpsc::Sender::clone(&tx); thread::spawn(move || { let vals = vec![ String::from("hola"), String::from("desde"), String::from("el"), String::from("hilo 1"), ]; for val in vals { tx1.send(val).unwrap(); thread::sleep(Duration::from_secs(1)); } }); thread::spawn(move || { let vals = vec![ String::from("vemos"), String::from("como "), String::from("trabaja"), String::from("hilo 2"), ]; for val in vals { tx.send(val).unwrap(); thread::sleep(Duration::from_secs(1)); } }); for received in rx { println!("Obetener mensaje {}", received); } }

Ejecutar

Analicemos un poco lo que hacemos:

use std::sync::mpsc;

Crea un nuevo canal asincrónico, devolviendo las mitades del transmisor / receptor. Todos los datos enviados en el remitente estarán disponibles en el receptor en el mismo orden en que fueron enviados, y ningún envío bloqueará el hilo de llamada. Aquí tx funcionará como transmisor de datos y rx como receptor.

let (tx, rx) = mpsc::channel();

Vamos mpsca usar y expandir el código, esta vez, antes de crear el primer hilo generado, llamamos clone al extremo emisor del canal. Esto nos dará un nuevo controlador de envío que podemos pasar al primer subproceso generado. Pasamos el extremo del envío original del canal a un segundo hilo generado. Esto nos da dos hilos, cada uno enviando mensajes diferentes al extremo receptor del canal.

let tx1 = mpsc::Sender::clone(&tx);

Eso logrará que tengamos una salida similar a esta:

Send & Sync


Los traits SendySync capturan y controlan las dos formas más comunes en las que se accede a un dato y se lo arroja a los hilos, dictando si es seguro transferir la propiedad o pasar una referencia a otro hilo.

Los traits son “marker traits”, lo que significa que no tienen métodos y no proporcionan inherentemente ninguna funcionalidad, solo son útiles para hacer cumplir invariantes relacionados con la concurrencia.

Con Send, indica que la propiedad del tipo que implementa el envío se puede transferir entre subprocesos.

El segundo de estos traits es llamado Sync. le indica al compilador que algo de este tipo no tiene posibilidad de introducir inseguridad en memoria cuando es usado de manera concurrente por múltiples hilos de ejecución.

Mutex


Para permitir que los hilos muten datos compartidos, necesitamos un tipo que pueda forzar el acceso mutuo exclusivo a los datos compartidos en tiempo de ejecución. La biblioteca estándar de Rust proporciona std :: sync :: Mutex <T> para este propósito.

Mutex es una abreviatura de exclusión mutua , ya que, en un mutex, solo un hilo puede acceder a algunos datos en un momento dado. Para acceder a los datos en un mutex, un subproceso primero debe indicar que desea acceder al solicitar la adquisición del bloqueo del mutex . El bloqueo es una estructura de datos que forma parte del mutex que realiza un seguimiento de quién tiene actualmente acceso exclusivo a los datos.

Los mutexes tienen fama de ser difíciles de usar porque debes recordar dos reglas:

  1. Debe intentar adquirir el bloqueo antes de usar los datos.
  2. Cuando haya terminado con los datos que guarda el mutex, debe desbloquear los datos para que otros hilos puedan adquirir el bloqueo.

Lo sé, hablar de concurrencia es un tema muy complicado, pero practicando lo dominarás. En esta clase tratamos de ver los traits, bibliotecas y métodos, que pueden ayudarnos a tener una mejor concurrencia dentro de nuestro programa.

Me gustaría saber cómo te sentiste con esta lección, en los comentarios cuéntame qué problemas has tenido cuando aprendes concurrencia en diferentes lenguajes de programación.