On dit que les boucles for-Julia sont aussi rapides que les opérations vectorisées et même plus rapides (si elles sont utilisées correctement). J'ai deux morceaux de code. L'idée est de trouver une statistique d'échantillon pour une séquence 0-1 donnée, qui est x (dans ces deux exemples j'essaie de trouver une somme, mais il y a des exemples plus compliqués, j'essaie juste de comprendre une signification générale des pièges de performance dans mon code). Le premier ressemble à:Langue de Julia. Comment battre les opérations vectorisées?
S = 2 * sum(x) - n
s_obs_new = abs(S)/sqrt(2 * n)
pval = erfc(s_obs_new)
et le second est quelque chose « naïf » et classique:
S = 0
for i in eachindex(x)
S += x[i]
end
S = 2 * S - n
s_obs_new = abs(S)/sqrt(2 * n)
pval = erfc(s_obs_new)
En utilisant @benchmark j'ai trouvé que la durée du premier exemple est d'environ 11,8 ms, et pour la seconde est de 38 ms. Cet exemple est très important pour moi, car il y a beaucoup d'autres endroits, où la vectorisation n'est pas possible, donc je veux faire des calculs de manière "dévoralisée" aussi vite qu'en vectorisé.
Y a-t-il des idées pour lesquelles le code devectorisé est probablement 4x fois plus lent que vectorisé? La stabilité de type est OK, il n'y a pas d'allocation grande mémoire inutiles et etc.
Le code pour la première fonction est:
function frequency_monobit_test1(x :: Array{Int8, 1}, n = 0)
# count 1 and 0 in sequence, we want the number
# of 1's and 0's to be approximately the same
# reccomendation n >= 100
# decision Rule(at 1% level): if pval < 0.01 -> non-random
if (n == 0)
n = length(x)
end
S = 2 * sum(x) - n
s_obs_new = abs(S)/sqrt(2 * n)
pval = erfc(s_obs_new)
return pval
Le second est:
function frequency_monobit_test2(x :: Array{Int8, 1}, n = 0)
# count 1 and 0 in sequence, we want the number
# of 1's and 0's to be approximately the same
# reccomendation n >= 100
# decision Rule(at 1% level): if pval < 0.01 -> non-random
if (n == 0)
n = length(x)
end
S = 0
@inbounds for i in eachindex(x)
S += x[i]
end
S = 2 * S - n
s_obs_new = abs(S)/sqrt(2 * n)
pval = erfc(s_obs_new)
return pval
D'abord, les [Conseils de performance] officielles (https://docs.julialang.org/en/stable/manual/performance-tips/) sont importants pour lire –
Une autre chose à faire est de mettre '@inbounds @ simd' devant l'instruction 'for' –
Veuillez nous montrer le code que vous utilisez pour obtenir les repères. –