Saltar al contenido

Lección 14 de 19 · Lectura y práctica

Analizar y Mejorar el Rendimiento de un Código Existente

Tipo de lección: VideoConcepto claveEn sistemas de baja latencia, el rendimiento no es solo una optimización, es un requisito de diseño. Analizar y mejorar el rendimiento implica identificar cuellos de botella en tiempo real y.

Del concepto a la práctica

Taller de esta lección

Antes de cambiar código, formula una hipótesis observable: por ejemplo, una asignación dentro de un bucle de 10 000 registros. La mejora debe mantener la misma salida y aislar esa causa.

Ejemplo resuelto

En vez de construir un Vec temporal por cada lote, se puede reutilizar un buffer reservado. Si cada lote contiene [2,4,6], el resultado sigue siendo suma 12.

Pruébalo

  1. Ejecuta la versión original con una entrada fija y guarda su salida.

  2. Mide y localiza la asignación o copia dominante.

  3. Reutiliza capacidad sin conservar datos del lote anterior.

Comprueba tu resultado

Cada lote [2,4,6] debe producir 12 antes y después.

Error frecuente: llamar “optimización” a quitar una validación; corrección: conserva la precondición o demuestra que ya se garantiza.

Ejercicio: procesa dos lotes [1,1] y [5,2] con el mismo buffer. Resultado esperado: resultados 2 y 7, longitud reiniciada entre lotes y ninguna mezcla de registros.

Vec::clear retira elementos y conserva capacidad, pero no garantiza que sus destructores o valores anidados no asignen/liberen memoria. En este fixture usa números y reserva la capacidad máxima de lote antes de medir. No presentes cero asignaciones a partir de mirar solo len; utiliza una medición adecuada. Reutilizar un buffer entre hilos exige ownership exclusivo o sincronización, no un Vec global mutable.

Diagrama de decisión con ramas Sí y No y un bucle que procesa cada elemento de una lista.
CursaloMapa de práctica
Cómo avanza un programa

Una condición decide qué camino ejecuta el programa. Un bucle repite una operación mientras queden elementos, y termina cuando la lista se agota. Separar ambas ideas ayuda a seguir el flujo y comprobar casos límite.

Ver la infografía en tamaño completo ↗
Fuentes para profundizar

Tipo de lección: Video

Concepto clave

En sistemas de baja latencia, el rendimiento no es solo una optimización, es un requisito de diseño. Analizar y mejorar el rendimiento implica identificar cuellos de botella en tiempo real y aplicar soluciones que reduzcan la latencia sin comprometer la seguridad. Piensa en esto como un cirujano que opera un corazón: no solo necesita saber anatomía, sino también cómo cada movimiento afecta el flujo sanguíneo en milisegundos.

En Rust, esto se traduce en entender cómo el compilador optimiza el código, cómo la memoria se gestiona en el stack vs heap, y cómo las decisiones de diseño impactan en el tiempo de ejecución. Un sistema de alta seguridad añade otra capa: las optimizaciones no deben introducir vulnerabilidades. Por ejemplo, usar unsafe puede mejorar el rendimiento, pero si se usa incorrectamente, compromete la seguridad.

Cómo funciona en la práctica

Vamos a analizar un fragmento de código Rust que procesa datos de sensores en tiempo real. Supongamos que tenemos una función que calcula el promedio de lecturas:

fn calcular_promedio(lecturas: &Vec<f64>) -> f64 {
    let mut suma = 0.0;
    for lectura in lecturas {
        suma += lectura;
    }
    suma / lecturas.len() as f64
}

Paso 1: Usa herramientas como cargo bench o perf para medir el tiempo de ejecución. En este caso, el bucle es ineficiente porque itera sobre un Vec, lo que puede causar caché misses.

Paso 2: Optimiza usando iteradores y operaciones vectorizadas:

fn calcular_promedio_optimizado(lecturas: &[f64]) -> f64 {
    lecturas.iter().sum::<f64>() / lecturas.len() as f64
}

Paso 3: Verifica que la optimización no afecte la seguridad—en este caso, al usar slices en lugar de Vec, mejoramos el rendimiento sin riesgos.

Caso de estudio

Imagina un sistema de trading de alta frecuencia que procesa órdenes en microsegundos. El código original usa Arc<Mutex<T>> para compartir datos entre hilos, pero esto introduce latencia por bloqueos.

Solución: Cambia a crossbeam-channel para comunicación sin bloqueo, reduciendo la latencia de 50μs a 10μs. Datos clave:

EnfoqueLatenciaSeguridad
Arc<Mutex<T>>50μsAlta
crossbeam-channel10μsAlta
En sistemas críticos, cada microsegundo cuenta. Optimizar la sincronización puede ser la diferencia entre ganar o perder una operación.

Errores comunes

  • Optimizar prematuramente: Escribir código complejo sin medir primero. Solución: Usa profiling antes de optimizar.
  • Ignorar el costo de allocaciones: Crear muchos objetos en el heap aumenta la latencia. Solución: Prefiere el stack cuando sea posible.
  • Usar unsafe sin justificación: Introducir código inseguro por rendimiento, sin evaluar alternativas seguras. Solución: Explora opciones como #[inline] o iteradores primero.
  • No considerar el impacto en caché: Estructuras de datos mal alineadas causan caché misses. Solución: Usa #[repr(C)] o herramientas como cachegrind.

Checklist de dominio

  1. ¿Has medido el rendimiento con herramientas como perf o flamegraph?
  2. ¿Has identificado y eliminado cuellos de botella en bucles o allocaciones?
  3. ¿Has evaluado el uso de unsafe vs alternativas seguras?
  4. ¿Has optimizado estructuras de datos para mejorar la localidad de caché?
  5. ¿Has probado el código en un entorno similar al de producción?
  6. ¿Has documentado las optimizaciones y su impacto en la seguridad?
  7. ¿Has revisado que las optimizaciones no introduzcan race conditions?

Optimizar un procesador de paquetes de red

En este ejercicio, optimizarás un código Rust que procesa paquetes de red para reducir la latencia. Sigue estos pasos:

  1. Descarga el código base desde el repositorio proporcionado (simulado aquí). Contiene una función procesar_paquete que analiza cabeceras de paquetes IP.
  2. Usa cargo bench para medir el tiempo actual de procesamiento por paquete. Anota los resultados.
  3. Identifica ineficiencias: revisa el código para allocaciones innecesarias, bucles lentos o uso de tipos pesados.
  4. Aplica al menos dos optimizaciones: por ejemplo, cambiar Vec a slices, usar iteradores, o reducir copias de datos.
  5. Vuelve a medir el rendimiento con cargo bench y compara los resultados. Asegúrate de que la seguridad no se vea comprometida.
  6. Escribe un breve informe explicando tus cambios y el impacto en la latencia.
Pistas
  • Considera usar &[u8] en lugar de Vec para evitar allocaciones.
  • Revisa si puedes precomputar valores constantes para reducir cálculos en tiempo de ejecución.
  • Usa #[inline] en funciones pequeñas que se llaman frecuentemente.

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.

Sigue con Rust para Sistemas de Baja Latencia y Alta Seguridad

Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.

Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.

01 / ELEGIR UNA RUTA

El próximo paso

Aprende IA mientras construyes algo que sí necesitas.

Empieza por el curso inicial o explora el catálogo para encontrar una práctica alineada con tu trabajo.