考虑以下对四个复杂矩阵进行操作的简单 Julia 代码:
n = 400
z = eye(Complex{Float64},n)
id = eye(Complex{Float64},n)
fc = map(x -> rand(Complex{Float64}), id)
cr = map(x -> rand(Complex{Float64}), id)
s = 0.1 + 0.1im
@time for j = 1:n
for i = 1:n
z[i,j] = id[i,j] - fc[i,j]^s * cr[i,j]
end
end
Run Code Online (Sandbox Code Playgroud)
尽管所有变量都是预先分配的,但时间显示了几百万次内存分配:
0.072718 seconds (1.12 M allocations: 34.204 MB, 7.22% gc time)
Run Code Online (Sandbox Code Playgroud)
如何避免所有这些分配(和 GC)?
高性能 Julia 代码的首要提示之一是避免使用全局变量。仅此一项就可以减少分配7次数。如果必须使用全局变量,提高其性能的一种方法是使用const. 使用const可以防止类型更改,但可以通过警告更改值。
在不使用函数的情况下考虑这个修改后的代码:
const n = 400
z = Array{Complex{Float64}}(n,n)
const id = eye(Complex{Float64},n)
const fc = map(x -> rand(Complex{Float64}), id)
const cr = map(x -> rand(Complex{Float64}), id)
const s = 0.1 + 0.1im
@time for j = 1:n
for i = 1:n
z[i,j] = id[i,j] - fc[i,j]^s * cr[i,j]
end
end
Run Code Online (Sandbox Code Playgroud)
时间显示了这个结果:
0.028882 seconds (160.00 k allocations: 4.883 MB)
Run Code Online (Sandbox Code Playgroud)
不仅分配次数变7 times少了,执行速度也变2.2 times快了。
现在让我们将第二个技巧应用于高性能 Julia 代码;把所有的东西都写在函数中。将上述代码写入函数z_mat(n):
function z_mat(n)
z = Array{Complex{Float64}}(n,n)
id = eye(Complex{Float64},n)
fc = map(x -> rand(Complex{Float64}), id)
cr = map(x -> rand(Complex{Float64}), id)
s = 1.0 + 1.0im
@time for j = 1:n
for i = 1:n
z[i,j] = id[i,j] - fc[i,j]^s * cr[i,j]
end
end
end
Run Code Online (Sandbox Code Playgroud)
和跑步
z_mat(40)
0.000273 seconds
@time z_mat(400)
0.027273 seconds
0.032443 seconds (429 allocations: 9.779 MB)
Run Code Online (Sandbox Code Playgroud)
这2610 times比整个函数的原始代码分配更少,因为循环单独执行零分配。