¿Qué es Julia? Un nuevo enfoque de la computación numérica

Julia es un lenguaje de programación dinámico de código abierto, de alto nivel y alto rendimiento para computación numérica. Tiene la conveniencia de desarrollo de un lenguaje dinámico con el rendimiento de un lenguaje compilado de tipo estático, gracias en parte a un compilador JIT basado en LLVM que genera código de máquina nativo, y en parte a un diseño que implementa la estabilidad de tipos a través de la especialización a través de múltiples dispatch, que facilita la compilación en un código eficiente.

En la publicación del blog que anunciaba el lanzamiento inicial de Julia en 2012, los autores del lenguaje — Jeff Bezanson, Stefan Karpinski, Viral Shah y Alan Edelman — declararon que pasaron tres años creando Julia porque eran codiciosos . Estaban cansados ​​de las compensaciones entre Matlab, Lisp, Python, Ruby, Perl, Mathematica, R y C, y querían un solo lenguaje que fuera bueno para la computación científica, el aprendizaje automático, la minería de datos, el álgebra lineal a gran escala. , computación paralela y computación distribuida.

¿Para quién es Julia? Además de ser atractiva para los científicos e ingenieros de investigación, Julia también es atractiva para los científicos de datos y para los analistas y quants financieros.

Los diseñadores del lenguaje y otros dos fundaron Julia Computing en julio de 2015 para "desarrollar productos que hagan que Julia sea fácil de usar, de implementar y de escalar". En el momento de escribir este artículo, la empresa cuenta con 28 empleados y clientes que van desde laboratorios nacionales hasta bancos, economistas e investigadores de vehículos autónomos. Además de mantener los repositorios de código abierto de Julia en GitHub, Julia Computing ofrece productos comerciales, incluido JuliaPro, que viene en versiones gratuitas y de pago.

¿Por qué Julia?

Julia "tiene como objetivo crear una combinación sin precedentes de facilidad de uso, potencia y eficiencia en un solo idioma". Para el tema de la eficiencia, considere el siguiente gráfico:

Julia Computación

Puntos de referencia de Julia

Lo que estamos viendo aquí es que el código de Julia puede ser más rápido que C para algunos tipos de operaciones y no más de unas pocas veces más lento que C para otros. Compare eso con, digamos, R, que puede ser casi 1000 veces más lento que C para algunas operaciones.

Tenga en cuenta que una de las pruebas más lentas para Julia es la recursividad de Fibonacci; eso se debe a que Julia actualmente carece de optimización de recursividad de cola. La recursividad es intrínsecamente más lenta que los bucles. Para los programas reales de Julia que desea ejecutar en producción, querrá implementar la forma de bucle (iteración) de dichos algoritmos.

Recopilación de Julia JIT

El enfoque del compilador JIT (just-in-time) tiene un costo en comparación con un intérprete puro: el compilador tiene que analizar el código fuente y generar código de máquina antes de que su código pueda ejecutarse. Eso puede significar un tiempo de inicio notable para los programas de Julia la primera vez que se ejecuta cada función y macro en una sesión. Entonces, en la captura de pantalla a continuación, vemos que la segunda vez que generamos un millón de números de coma flotante aleatorios, el tiempo que toma es un orden de magnitud menor que en la primera ejecución. Tanto la @timemacro como la rand()función debían compilarse la primera vez a través del código, porque las bibliotecas de Julia están escritas en Julia.

julia> @time rand (10 ^ 6);

  0,62081 segundos (14,44 k asignaciones: 8,415 MiB)

julia> @time rand (10 ^ 6);

  0,004881 segundos (7 asignaciones: 7,630 MiB)

Los fanáticos de Julia afirman, de diversas maneras, que tiene la facilidad de uso de Python, R o incluso Matlab. Estas comparaciones merecen un escrutinio, ya que el lenguaje Julia es elegante, potente y está orientado a la informática científica, y las bibliotecas proporcionan una amplia gama de funciones de programación avanzada.

Ejemplo de Julia

Como ejemplo rápido de lenguaje de Julia, considere el siguiente código de referencia de conjunto de Mandelbrot:

Como puede ver, la aritmética de números complejos está integrada en el lenguaje, al igual que las macros para pruebas y cronometraje. Como también puede ver, los puntos y comas finales que afectan a los lenguajes tipo C, y los paréntesis anidados que afectan a los lenguajes tipo Lisp, están ausentes en Julia. Tenga en cuenta que mandelperf()se llama dos veces, en las líneas 61 y 62. La primera llamada prueba la exactitud del resultado y realiza la compilación JIT; la segunda llamada obtiene el tiempo.

Programación Julia

Julia tiene muchas otras características que vale la pena mencionar. Por un lado, los tipos definidos por el usuario son tan rápidos y compactos como los integrados. De hecho, puede declarar tipos abstractos que se comportan como tipos genéricos, excepto que se compilan para los tipos de argumentos que se pasan.

Por otro lado, la vectorización de código incorporada de Julia significa que no hay necesidad de que un programador vectorice el código para el rendimiento; el código desvectorizado ordinario es rápido. El compilador puede aprovechar las instrucciones y registros SIMD, si están presentes en la CPU subyacente, y desenrollar los bucles en un proceso secuencial para vectorizarlos tanto como lo permita el hardware. Puede marcar los bucles como vectorizables con la @simdanotación.

Paralelismo de Julia

Julia también fue diseñada para paralelismo y computación distribuida, usando dos primitivas: referencias remotas y llamadas remotas. Las referencias remotas vienen en dos sabores:  Future y  RemoteChannel. A Futurees el equivalente a JavaScript promise; a RemoteChanneles regrabable y se puede utilizar para la comunicación entre procesos, como Unix pipeo Go channel. Suponiendo que ha iniciado Julia con varios procesos (por ejemplo, julia -p 8para una CPU de ocho núcleos como un Intel Core i7), puede ejecutar llamadas de función @spawno remotecall()en otro proceso de Julia de forma asincrónica, y luego fetch()las Futuredevuelve cuando desee sincronizar y usar el resultado.

Si no necesita ejecutar en varios núcleos, puede utilizar subprocesos ligeros "verdes", llamados Task()en Julia y una corrutina en algunos otros idiomas. A Task()o @taskfunciona junto con a Channel, que es la versión de proceso único de RemoteChannel.

Sistema de tipo Julia

Julia tiene un sistema de tipos discreto pero potente que es dinámico con inferencia de tipos en tiempo de ejecución de forma predeterminada, pero permite anotaciones de tipos opcionales. Esto es similar a TypeScript. Por ejemplo:

julia> (1 + 2) :: AbstractFloat

ERROR: TypeError: typeassert: se esperaba AbstractFloat, obtuvo Int64

julia> (1 + 2) :: Int

3

Aquí estamos afirmando un tipo incompatible la primera vez, provocando un error y un tipo compatible la segunda vez.

Julia cuerdas

Julia tiene un soporte eficiente para cadenas y caracteres Unicode, almacenados en formato UTF-8, así como un soporte eficiente para caracteres ASCII, ya que en UTF-8 los puntos de código menores a 0x80 (128) están codificados en un solo carácter. De lo contrario, UTF-8 es una codificación de longitud variable, por lo que no puede asumir que la longitud de una cadena de Julia es igual al índice del último carácter.

El soporte completo para UTF-8 significa, entre otras cosas, que puede definir fácilmente variables usando letras griegas, lo que puede hacer que el código científico de Julia se parezca mucho a las explicaciones de las fórmulas de los libros de texto, por ejemplo sin(2π). Se transcode()proporciona una función para convertir UTF-8 hacia y desde otras codificaciones Unicode.

Funciones C y Fortran

Julia puede llamar a las funciones C y Fortran directamente, sin necesidad de envoltorios ni API especiales, aunque es necesario conocer el nombre de la función "decorada" emitida por el compilador Fortran. La función externa de C o Fortran debe estar en una biblioteca compartida; utiliza la ccall()función de Julia para la llamada real. Por ejemplo, en un sistema similar a Unix, puede usar este código de Julia para obtener el valor de una variable de entorno usando la getenvfunción en libc:

función getenv (var :: AbstractString)

     val = ccall ((: getenv, "libc"),

                 Cstring, (Cstring,), var)

     si val == C_NULL

         error ("getenv: variable indefinida:", var)

     fin

     unsafe_string (val)

fin

julia> getenv ("CONCHA")

"/ bin / bash"

Macros julia

Julia tiene macros similares a Lisp, a diferencia de los preprocesadores de macros utilizados por C y C ++. Julia también tiene otras facilidades de metaprogramación, como reflexión, generación de código, objetos de símbolos (por ejemplo :foo) y expresión (por ejemplo :(a+b*c+1)) eval(), y funciones generadas. Las macros de Julia se evalúan en el momento del análisis.

Las funciones generadas, por otro lado, se expanden cuando se conocen los tipos de sus parámetros, antes de la compilación de la función. Las funciones generadas tienen la flexibilidad de las funciones genéricas (implementadas en C ++ y Java) y la eficiencia de las funciones fuertemente tipadas, al eliminar la necesidad de despacho en tiempo de ejecución para soportar el polimorfismo paramétrico.

Soporte de GPU

Julia tiene soporte para GPU usando, entre otros, el paquete de aprendizaje profundo MXNet, la biblioteca de arreglos de GPU ArrayFire, las bibliotecas de álgebra lineal y redes neuronales profundas cuBLAS y cuDNN, y el marco CUDA para computación GPU de propósito general. Los contenedores de Julia y sus respectivas bibliotecas se muestran en el siguiente diagrama.

Julia Computación

JuliaPro y Juno IDE

Puede descargar la línea de comandos gratuita de código abierto de Julia para Windows, MacOS, Linux genérico o FreeBSD genérico desde el sitio de idiomas de Julia. Puede clonar el repositorio de código fuente de Julia desde GitHub.

Alternativamente, puede descargar JuliaPro de Julia Computing. Además del compilador, JuliaPro le ofrece el IDE de Juno basado en Atom (que se muestra a continuación) y más de 160 paquetes seleccionados, que incluyen visualización y trazado.

Más allá de lo que incluye JuliaPro gratuita, puede agregar suscripciones para soporte empresarial, funcionalidad financiera cuantitativa, soporte de base de datos y análisis de series de tiempo. JuliaRun es un servidor escalable para un clúster o nube.

Cuadernos Jupyter e IJulia

Además de usar Juno como su IDE de Julia, puede usar Visual Studio Code con la extensión de Julia (que se muestra directamente a continuación) y cuadernos de Jupyter con el kernel de IJulia (que se muestran en la segunda y tercera capturas de pantalla a continuación). Es posible que deba instalar cuadernos de Jupyter para Python 2 o (preferiblemente) Python 3 con Anaconda o pip.

JuliaBox

Puede ejecutar Julia en cuadernos de Jupyter en línea utilizando JuliaBox (que se muestra a continuación), otro producto de Julia Computing, sin realizar ninguna instalación en su máquina local. JuliaBox incluye actualmente más de 300 paquetes, ejecuta Julia 0.6.2 y contiene docenas de cuadernos de tutoriales de Jupyter. La lista de nivel superior de carpetas de tutoriales se muestra a continuación. El nivel gratuito de acceso a JuliaBox le brinda sesiones de 90 minutos con tres núcleos de CPU; la suscripción personal de $ 14 por mes le brinda sesiones de cuatro horas con cinco núcleos; y la suscripción profesional de $ 70 por mes le brinda sesiones de ocho horas con 32 núcleos. El acceso a la GPU aún no está disponible en junio de 2018.

Paquetes Julia

Julia "camina como Python, pero corre como C." Como escribió mi colega Serdar Yegulalp en diciembre de 2017, Julia está comenzando a desafiar a Python en la programación de ciencia de datos, y ambos lenguajes tienen ventajas. Como una indicación de la rápida maduración del apoyo a la ciencia de datos en Julia, considere que ya hay dos libros titulados Julia para la ciencia de datos , uno de Zacharias Voulgaris y el otro de Anshul Joshi, aunque no puedo hablar de la calidad de ninguno de los dos. uno.

Si observa los paquetes de Julia mejor calificados en general de Julia Observer, que se muestran a continuación, verá un kernel de Julia para portátiles Jupyter, el paquete de gráficos Gadfly (similar a ggplot2en R), una interfaz de trazado genérica, varios deep learning y machine paquetes de aprendizaje, solucionadores de ecuaciones diferenciales, DataFrames, modelos de equilibrio dinámico estocástico general (DSGE) de la Fed de Nueva York, un lenguaje de modelado de optimización e interfaces para Python y C ++. Si avanza un poco más en esta lista general, también encontrará QuantEcon, PyPlot, ScikitLearn, un paquete bioinformático y una implementación de listas perezosas para programación funcional.

Si los paquetes de Julia no son suficientes para sus necesidades y la interfaz de Python no lo lleva a donde desea ir, también puede instalar un paquete que le brinde interfaces genéricas para R (RCall) y Matlab.

Julia para analistas financieros y quants

Quants y analistas financieros encontrarán muchos paquetes gratuitos para acelerar su trabajo, como se muestra en la captura de pantalla a continuación. Además, Julia Computing ofrece la suite JuliaFin, que consta de Miletus (un DSL para contratos financieros),  JuliaDB (una base de datos distribuida y en memoria de alto rendimiento),  JuliaInXL (llame a Julia desde hojas de Excel) y  conectividad Bloomberg (acceso a datos reales). (datos de mercado históricos y temporales).