performance - Rendimiento de Julia(Julia-lang) en comparación con Fortran y Python
fortran77 (2)
He seguido el proyecto de Julia desde hace un tiempo y tengo algunos comentarios sobre el código que pueden ser relevantes.
- Parece que ejecuta una cantidad sustancial del código en alcance global. El entorno global es actualmente muy lento en Julia, porque los tipos de todas las variables deben verificarse en cada iteración. Los bucles generalmente deberían escribirse en una función.
- Parece que usa el corte de matriz. Actualmente eso hace una copia porque Julia no tiene vistas rápidas de Array. Puede intentar cambiarlos por subcampos, pero actualmente son mucho más lentos de lo que deberían.
El tiempo de carga de PyPlot (y de cualquier otro paquete) es un problema conocido, y se debe a que el análisis y la compilación del código de Julia a código de máquina lleva mucho tiempo. Hay ideas acerca de tener un caché para este proceso, de modo que este proceso se vuelva instantáneo, pero aún no está terminado. La biblioteca Base está actualmente en caché en estado compilado, por lo que la mayoría de la infraestructura se encuentra ahora en la rama principal.
AGREGADO : Intenté ejecutar la prueba en una función aislada y obtuve estos resultados. Ver esta esencia
Análisis:
elapsed time: 0.334042578 seconds (11797548 bytes allocated)
Y arme runas consecutivas del bucle de prueba principal.
elapsed time: 0.62999287 seconds (195210884 bytes allocated)
elapsed time: 0.39398753 seconds (184735016 bytes allocated)
elapsed time: 0.392036875 seconds (184735016 bytes allocated)
Observe cómo la sincronización mejoró después de la primera ejecución, porque el código compilado se utilizó de nuevo.
Actualización 2 Con un manejo mejorado de la memoria (asegure la reutilización de matrices, porque la asignación no se copia), reduje el tiempo a 0.2 segundos (en mi máquina). Definitivamente, se puede hacer más para evitar la asignación de nuevas matrices, pero luego comienza a ser un poco complicado.
Esta línea no hace lo que piensas:
vx_old = vx
pero haz lo que quieras:
copy!(vx_old, vx)
y devectorizar un bucle
x += 0.5*(vx + vx_old)*delta_t
y += 0.5*(vy + vy_old)*delta_t
a:
for i = 1:nvortex
x[i] += 0.5*(vx[i] + vx_old[i])*delta_t
y[i] += 0.5*(vy[i] + vy_old[i])*delta_t
end
Adapte un programa simple para calcular y trazar los vórtices de movimiento de Julia para probar el idioma, también lo escribí en Python sin ningún motivo en particular.
(Descargo de responsabilidad: 1. Cada comparación de rendimiento en stackoverflow que leo se cierra de golpe por no ser completa / correcta / bien escrita / relevante, etc. etc. - No pretendo que esta sea una comparación real, solo me gustaría saber cómo hacer la Julia más rápido. 2. Sé que Python podría ser optimizado, implementado en Cython, etc., eso no es parte de esta discusión, solo está aquí para una referencia de funciones equivalentes en Julia y Python.)
El código y los resultados de rendimiento se pueden ver en una esencia .
El rendimiento de Julia es significativamente más lento que Fortran. Los tiempos necesarios para realizar el cálculo en sí son (50000 pasos de tiempo):
Fortran: 0.051s
Julia: 2.256s
Python: 30.846s
Julia es mucho más lenta (~ 44 veces más lenta) que Fortran, la brecha se estrecha pero sigue siendo significativa con 10 veces más pasos de tiempo ( 0.50s vs 15.24s
).
Estos resultados son significativamente diferentes a los que se muestran en la página principal de julia . ¿Qué estoy haciendo mal? ¿Podría arreglar el Julia para que sea significativamente más rápido?
Leí detenidamente la página Julia Performance Tips y el código detrás de la comparación en la página de inicio de Julia, y no hay nada que se pueda destacar para solucionarlo.
También, curiosamente, Julia es extremadamente lenta al cargar PyPlot ( 5secs
ish !!) y mucho más lenta que Python para leer el archivo de texto. ¿Podría hacer algo para mejorar estas cosas?
Tenga en cuenta que los tiempos anteriores no muestran el tiempo de carga para Julia y Python, es solo el tiempo crudo que toma el cómputo AFAIK - vea el código. Para fortran, es todo. El trazado se ha desactivado, aproximadamente, en cada caso para permitir la comparación de velocidad.
Computadora: Intel i7-3770, 16GB ram, SSD HD, SO: Ubuntu 13.10 64bit., Fortran: gfortran, GNU Fortran (Ubuntu / Linaro 4.8.1-10ubuntu9) 4.8.1, Julia: Versión 0.3.0-prerelease + 396 (2013-12-12 00:18 UTC), Commit c5364db * (maestro de 0 días), x86_64-linux-gnu, Python: 2.7.5+
Actualizar:
Basado en el consejo de ivarne reescribí el guión de Julia (actualizado en la parte superior): encapsulando el trabajo grupal en funciones, declarando el tipo de todo y dividiendo los diferentes elementos de las matrices en diferentes matrices donde corresponda. (Incluí Float64 en bastantes lugares mientras probaba Float32 para ver si eso ayudaba, no lo hacía la mayor parte del tiempo).
Los resultados son los siguientes:
50,000
pasos de tiempo:
Fortran: 0.051s (entire programme)
Julia: raw calc.: 0.201s, calc. and return (?): 0.758s, total exec.: 6.947s
500,000
pasos de tiempo:
Fortran: 0.495s (entire programme)
Julia: raw calc.: 1.547s, calc. and return (?): 2.094s, total exec.: 8.521s
En conclusión:
Puedes acelerar a Julia bastante.
Puede afectar significativamente la velocidad aparente de Julia dependiendo de cómo mida su rendimiento.
@ivarne cubre esto pero tiene un poco más de atención:
julia> @time x=[1:10000];
elapsed time: 1.544e-5 seconds (80120 bytes allocated)
julia> @time y = x[1:10000];
elapsed time: 2.6857e-5 seconds (80120 bytes allocated)
Guau. Eso es mucho tiempo y memoria.
julia> @time z = sub(x,1:10000);
elapsed time: 6.239e-6 seconds (296 bytes allocated)
Mucho mejor. ¿Por qué no [:]
hace lo que hace sub
? No lo sé. Bueno, algo así como Cuando vaya al índice z[10]
Julia piensa que, hrmm, z es como x, excepto que los índices están desplazados por 0, por lo que z[10]
es x[10+0]
. Ahí tienes. Esa pequeña adición adicional te costará a largo plazo si haces una gran cantidad de indexación. Para solucionar esto, necesitas un concepto como punteros que sea contrario a la religión de Julia.
Actualizar Julia ahora se deprecia [:]
(versión 0.4.0)
julia> @time x=[1:10000];
WARNING: [a] concatenation is deprecated; use collect(a) instead
in depwarn at deprecated.jl:73
in oldstyle_vcat_warning at ./abstractarray.jl:29
in vect at abstractarray.jl:32
while loading no file, in expression starting on line 155
0.530051 seconds (180.12 k allocations: 9.429 MB, 5.26% gc time)
julia> @time x=[1:10000];
WARNING: [a] concatenation is deprecated; use collect(a) instead
in depwarn at deprecated.jl:73
in oldstyle_vcat_warning at ./abstractarray.jl:29
in vect at abstractarray.jl:32
while loading no file, in expression starting on line 155
0.001373 seconds (303 allocations: 714.656 KB)
recoger es más rápido
julia> @ time x=collect(1:10000);
0.003991 seconds (35 allocations: 80.078 KB)
julia> @ time x=collect(1:10000);
0.000031 seconds (8 allocations: 78.406 KB)
comparable a SubArrays
julia> @time z = sub(x,1:10000);
0.067002 seconds (36.27 k allocations: 1.792 MB)
julia> @time z = sub(x,1:10000);
0.000016 seconds (7 allocations: 288 bytes)