如何避免Julia中的内存分配?

如何避免Julia中的内存分配?,julia,Julia,考虑以下在四个复杂矩阵上运行的简单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] =

考虑以下在四个复杂矩阵上运行的简单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
计时显示了数百万内存分配,尽管所有变量都已预分配:

0.072718 seconds (1.12 M allocations: 34.204 MB, 7.22% gc time)

如何避免所有这些分配(和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 
计时显示此结果:

0.028882 seconds (160.00 k allocations: 4.883 MB)
不仅分配的数量减少了7倍,而且执行速度加快了2.2倍

现在让我们应用高性能Julia代码的第二个技巧;用函数写每件事。将上述代码写入函数
z_mat(n)

跑步

z_mat(40)
  0.000273 seconds
@time z_mat(400)
  0.027273 seconds
  0.032443 seconds (429 allocations: 9.779 MB)

这是整个函数的
2610倍
分配比原始代码少,因为循环本身没有分配。

您可以将特定的双循环重写为
id.-fc.^s.*cr
-这将减少分配。这里有很多提示可能会有所帮助。但是评估全局工作区中的所有内容可能是第一件要看的事情at@AlexRiley不正确:当循环已被取消分区时,广播不会削减分配。这可能是由于全局计时的缘故。@AlexRiley使用点运算符是我最初尝试的事情,但这并没有减少分配。正如下面的答案所示,是全局变量导致了问题……好的,感谢您提供的代码示例,全局变量似乎是罪魁祸首。也许我应该采用约定,将Julia脚本的主要部分放入一个主函数中……您能解释一下为什么使用全局函数会导致分配,为什么将代码放入函数中会阻止分配吗?从我使用其他语言的经验来看,这种行为并不明显。@JosephGarvin你们找到问题的答案了吗?我也有同样的想法doubt@tejas不幸的是我没有我仍然没有idea@JosephGarvin,请看这里
z_mat(40)
  0.000273 seconds
@time z_mat(400)
  0.027273 seconds
  0.032443 seconds (429 allocations: 9.779 MB)