Programación y desarrollo de software

Cómo usar Numba para acelerar modelos computacionales de Python en los servicios financieros

Chad Schuster, de Milliman, explica cómo Numba puede convertir partes de programas de Python en código optimizado mediante LLVM, aprovechando el procesamiento paralelo y las unidades GPU. El experimento muestra importantes mejoras de rendimiento, pero también revela limitaciones en la programación orientada a objetos, la inferencia de tipos y el tiempo de compilación, lo que hace que elegir las partes adecuadas para acelerar sea un factor decisivo.

2026-08-27
6 min de lectura
13 visitas
فريق تحرير certi.news
Cómo usar Numba para acelerar modelos computacionales de Python en los servicios financieros

Chad Schuster, Principal en la práctica de gestión de riesgos financieros de Milliman, presentó una experiencia práctica para construir modelos computacionales de alto rendimiento usando Python y Numba, en lugar de depender completamente de aplicaciones escritas en C++. La experiencia parte de un problema común en los servicios financieros: los modelos que simulan flujos de efectivo a través de un gran número de escenarios necesitan una gran capacidad de cálculo, mientras que los equipos desean conservar la velocidad de desarrollo y la facilidad de mantenimiento de Python.

El problema adquiere especial importancia en los modelos de seguros de vida y productos de jubilación como las annuities, donde los cálculos se utilizan para valorar obligaciones futuras y ejecutar múltiples escenarios. Según la presentación, las compañías de seguros han dependido históricamente de redes locales con entre 5.000 y 10.000 nodos, pero la migración a la nube hizo más evidentes el tiempo de ejecución y el coste de cada operación en las decisiones de infraestructura.

¿Qué aporta Numba a Python?

La Python tradicional, o CPython, interpreta el código durante la ejecución, mientras que los lenguajes compilados como C++ convierten el código en instrucciones de máquina antes de ejecutarlo. Numba intenta reducir esta brecha mediante la compilación Just-in-Time, ya que compila las funciones aptas durante la ejecución del programa usando LLVM y después sustituye la función original por la ejecución compilada.

El desarrollador suele activar este proceso mediante decoradores de Python como JIT o njit. Numba trabaja a nivel de función: examina el código y lo convierte en una representación intermedia propia; después infiere los tipos de las variables, los parámetros y los valores de retorno, antes de reducir la representación a LLVM IR y realizar las optimizaciones necesarias. Si la función se invoca con tipos diferentes, Numba puede crear implementaciones compiladas especializadas para cada conjunto de tipos mediante lo que denomina polymorphic dispatch.

Las mejoras de rendimiento no son una cifra fija

En la prueba de concepto presentada por Schuster, Numba hizo que el programa fuera aproximadamente 75 veces más rápido que Python interpretada. En otro modelo, el resultado fue distinto: trasladar los cálculos numéricos intensivos a Numba en la CPU produjo una aceleración cercana al doble, y después pasar a una GPU produjo una aceleración adicional de 750 veces en esa ejecución concreta. La presentación señaló que este nivel de mejora hizo que la unidad GPU equivaliera aproximadamente a 750 núcleos utilizados en esa ejecución, con una reducción estimada del coste hasta alrededor de una décima parte.

Sin embargo, estos resultados no representan una promesa general para todas las aplicaciones. La mejora depende de la cantidad de código compilable, del volumen de operaciones de cálculo en comparación con las operaciones de entrada y salida, de la eficiencia de la Python original y de la capacidad de LLVM para optimizar el código generado. Además, el procesamiento en GPU no es adecuado para todos los algoritmos, por lo que se debe medir el cuello de botella real antes de rediseñar el modelo.

¿Qué cambia en la práctica para los equipos de ingeniería?

La experiencia recomienda mantener en Python las capas de preparación de datos y de entrada y salida, y trasladar a Numba únicamente la parte numéricamente intensiva siempre que sea posible. Este enfoque reduce el alcance de la reescritura y conserva gran parte del entorno de Python, al tiempo que concentra el esfuerzo de optimización en las funciones que consumen la mayor parte del tiempo de ejecución. Cuando las funciones numéricas son limitadas y claras, Schuster considera que probar Numba puede ser una opción directa para quienes desean permanecer dentro de Python.

En cambio, al introducir una lógica amplia y compleja en Numba, aumentan los costes de diseño y mantenimiento. La experiencia recurrió a arrays de NumPy, tuples y estructuras de datos sencillas, porque la compatibilidad de Numba no cubre todas las características de Python. Entre las limitaciones mencionadas están los diccionarios con tipos flexibles, las excepciones, los gestores de contexto, los cierres y las listas creadas mediante comprehensions, además de la compatibilidad limitada con algunas funciones habituales como print, sorted y getattr.

Limitaciones que deben tenerse en cuenta antes de adoptarla

La programación orientada a objetos sigue siendo un punto débil importante en esta experiencia. Numba ofrece funciones experimentales como jitclasses y structrefs para proporcionar un comportamiento similar al de los objetos, pero estas pueden cambiar entre versiones y no son compatibles con GPU, lo que hizo que no fueran adecuadas para el enfoque adoptado por el equipo. Por ello, la aplicación se orientó hacia un estilo más cercano a la programación funcional y a las estructuras de datos sencillas, aunque el diseño orientado a objetos era deseable por razones relacionadas con la mantenibilidad y la entrega de modelos a los clientes.

Asimismo, los errores de inferencia de tipos y los errores de lowering pueden ser difíciles de rastrear, especialmente en programas con muchas capas de llamadas. El error puede señalar una función alejada del lugar donde surgió realmente el problema. Una de las técnicas prácticas propuestas es usar JIT en lugar de njit cuando sea necesario, de modo que Numba pueda desactivarse temporalmente y volver a Python interpretada para facilitar la depuración, y después reactivarse la aceleración en la ejecución de producción.

También existe un tiempo inicial de compilación que se produce en la primera llamada a cada función, y que puede aumentar cuando la técnica de inlining se utiliza ampliamente. Se puede recurrir a la compilación anticipada Ahead-of-Time para evitar este retraso, pero esto puede reducir la capacidad del código para adaptarse al dispositivo real en comparación con la compilación Just-in-Time.

Lectura editorial: el valor principal de esta experiencia no es la cifra de 750 veces por sí misma, sino el método que vincula la medición del rendimiento con la división del modelo. Numba es adecuada cuando el cuello de botella es computacional y puede aislarse en funciones con tipos y estructuras claros; en cambio, convertir todo un sistema Python en código compilable puede trasladar el problema de la lentitud de ejecución a la complejidad del desarrollo y la depuración. Por ello, los equipos financieros y de ingeniería deben equilibrar la velocidad de ejecución, la mantenibilidad, el tiempo de compilación y la compatibilidad con GPU antes de considerarla un sustituto integral de C++ o de un rediseño más amplio del sistema.

Fuente de la noticia
InfoQ - Architecture Articles
Abrir fuente original ↗
ف
Autor

فريق تحرير certi.news

De la misma categoría

También te puede interesar

Ver todas las noticias