Saltar al contenido

Ficheros grandes

Leer un fichero de dos gigas en memoria es la forma más fácil de matar una aplicación. Flujos, progreso, cancelación y el camino que no pasa por el puente.

Los cuatro problemas

El patrón completo

Los cuatro juntos, que es como se escriben:

Rust
#[tauri::command]async fn procesar_archivo(    app: AppHandle,    estado: State<'_, Trabajos>,    origen: String,          // un identificador de dominio, no una ruta. Nivel 14.4) -> Result<Resumen, Error> {    let ruta = estado.resolver(&origen)?;      // la app decide qué fichero es    let cancelar = estado.nueva_bandera();    tauri::async_runtime::spawn_blocking(move || {        let total = std::fs::metadata(&ruta)?.len();        let mut leidos = 0u64;        let mut buffer = vec![0u8; 64 * 1024];        let mut f = File::open(&ruta)?;        let mut ultimo_aviso = 0u64;        loop {            if cancelar.load(Ordering::Relaxed) {                return Err(Error::Cancelado);            }            let n = f.read(&mut buffer)?;            if n == 0 { break; }            procesar_trozo(&buffer[..n])?;            leidos += n as u64;            // avisar cada 1%, no cada trozo: el puente no es para esto            if leidos - ultimo_aviso > total / 100 {                ultimo_aviso = leidos;                let _ = app.emit("progreso", leidos as f64 / total as f64);            }        }        Ok(resumen())    })    .await?}

Cuatro detalles del fragmento que son la lección entera:

  • El buffer se reutiliza. No se asigna uno por trozo.
  • La bandera se comprueba en cada vuelta, que es lo que hace cancelable el bucle. Sin eso, «cancelar» solo significa dejar de mirar.
  • El progreso se emite cada uno por ciento, no cada trozo. Un fichero de dos gigas con trozos de 64 KB son treinta mil vueltas: emitir en todas satura el puente y hace la operación más lenta que el trabajo real.
  • Y el comando recibe un identificador, no una ruta. El nivel 14.4 otra vez.

Los bytes no cruzan el puente

La decisión de arquitectura, y es la que más rendimiento y más seguridad da a la vez:

La pregunta que resuelve el diseño: ¿la interfaz necesita los bytes, o necesita mostrarlos? Casi siempre es lo segundo, y para mostrar hay dos caminos que no cruzan el puente.

Escribir grande

El mismo patrón al revés, con dos añadidos:

  • La escritura atómica del nivel 40.2 no siempre vale. Escribir dos gigas en un temporal y renombrar duplica el espacio ocupado durante la operación. Para exportaciones grandes suele aceptarse el riesgo y escribir directo, avisando de que si se interrumpe hay que repetir — pero es una decisión, no un descuido.
  • Y hay que comprobar el espacio libre antes de empezar, porque quedarse sin disco a mitad de una escritura de dos gigas deja al usuario sin espacio y sin resultado.