Muchos lenguajes de sistemas tienen soporte básico para operaciones de entrada/salida, pero a menudo no hacen una distinción clara entre enfoques sincrónicos y asincrónicos. Rust fue diseñado desde el principio para garantizar seguridad y rendimiento, incluida la gestión de E/S. Por lo tanto, la biblioteca estándar de Rust (std) solo implementa E/S sincrónica, mientras que el popular soporte asincrónico se ha separado en bibliotecas externas (por ejemplo, tokio, async-std).
La mezcla de enfoques de E/S sincrónica y asincrónica a menudo conduce a problemas de mantenimiento del código y problemas de seguridad y rendimiento, ya que estos enfoques tienen diferentes modelos de gestión de recursos, hilos y bloqueos. Por ejemplo, la lectura directa de un gran archivo o la espera de datos de la red puede bloquear el hilo de ejecución (incluido el hilo principal), lo que ralentiza la aplicación.
Rust ofrece una clara separación: Biblioteca estándar (std::io) — solo E/S sincrónica con tratamiento seguro de errores y control estricto de la propiedad de los recursos. Para soluciones asincrónicas, se utilizan bibliotecas externas y runtimes asincrónicos; proporcionan sus propios tipos y API, pero con una semántica de errores y seguridad similar.
Ejemplo de código para la lectura sincrónica de un archivo:
use std::fs::File; use std::io::{self, Read}; fn main() -> io::Result<()> { let mut file = File::open("foo.txt")?; let mut contents = String::new(); file.read_to_string(&mut contents)?; println!("{}", contents); Ok(()) }
Ejemplo de código para la lectura asincrónica de un archivo a través de tokio:
use tokio::fs::File; use tokio::io::AsyncReadExt; #[tokio::main] async fn main() -> tokio::io::Result<()> { let mut file = File::open("foo.txt").await?; let mut contents = String::new(); file.read_to_string(&mut contents).await?; println!("{}", contents); Ok(()) }
Características clave:
¿Se pueden mezclar tipos directamente (por ejemplo, File de std y File de tokio) para pasarlos entre funciones sincrónicas y asincrónicas?
No. Son incompatibles a nivel de API, y los tipos estándar no implementan traits asincrónicos.
¿Se bloquea el hilo std::thread::spawn en una función asincrónica si se llama a E/S sincrónica en ella?
Sí. Si se llama a E/S sincrónica en un entorno asincrónico, el hilo se bloqueará, lo que anula las ventajas de la asincronía.
¿Se puede usar async fn main sin un runtime (tokio o async-std)?
No. El punto de entrada asincrónico debe ejecutarse en un runtime especial; de lo contrario, el compilador no permitirá usar async fn main.
En un servidor multihilo en Rust, se utiliza la lectura sincrónica de std::io en manejadores de solicitudes asincrónicas. Esto bloquea el event loop, aumenta las latencias y el servidor no puede manejar cargas pico.
Ventajas:
Desventajas:
Se utilizan solo tipos asincrónicos para todas las operaciones de archivos y redes dentro del código asincrónico, controlando estrictamente los tipos y manejando errores a través de Result.
Ventajas:
Desventajas: