我有一个用 Julia 编写的模拟程序,它在主循环中执行与此相同的操作:
# Some fake data
M = [randn(100,100) for m=1:100, n=1:100]
W = randn(100,100)
work = zip(W,M)
result = mapreduce(x -> x[1]*x[2], +,work)
Run Code Online (Sandbox Code Playgroud)
换句话说,就是加权矩阵的简单求和。对上述代码进行计时,得出
0.691084 seconds (79.03 k allocations: 1.493 GiB, 70.59% gc time, 2.79% compilation time)
Run Code Online (Sandbox Code Playgroud)
我对大量的内存分配感到惊讶,因为这个问题应该可以就地解决。为了看看我对mapreduce的使用是否错误,我还测试了以下等效实现:
@time begin
res = zeros(100,100)
for m=1:100
for n=1:100
res += W[m,n] * M[m,n]
end
end
end
Run Code Online (Sandbox Code Playgroud)
这给了
0.442521 seconds (50.00 k allocations: 1.491 GiB, 70.81% gc time)
Run Code Online (Sandbox Code Playgroud)
因此,如果我用 C++ 或 Fortran 编写此代码,那么就地完成所有这些操作就会很简单。这在朱莉娅身上不可能吗?或者我在这里遗漏了什么......?
可以像这样就地完成:
function ws(W, M)
res = zeros(100,100)
for m=1:100
for n=1:100
@. res += W[m,n] * M[m, n]
end
end
return res
end
Run Code Online (Sandbox Code Playgroud)
时间是:
julia> @time ws(W, M);
0.100328 seconds (2 allocations: 78.172 KiB)
Run Code Online (Sandbox Code Playgroud)
请注意,为了就地执行此操作,我使用了广播(我也可以使用循环,但它是相同的)。
您的代码的问题在于:
res += W[m,n] * M[m,n]
Run Code Online (Sandbox Code Playgroud)
您将获得两种分配:
W[m,n] * M[m,n]会分配一个新矩阵。res += ...,会分配一个矩阵通过使用广播来@.执行就地操作,请参阅https://docs.julialang.org/en/v1/manual/mathematical-operations/#man-dot-operators了解更多说明。
另外请注意,我已将代码包装在函数内。如果您不这样做,则访问两者W并且M类型不稳定,这也会导致分配,请参阅https://docs.julialang.org/en/v1/manual/performance-tips/#Avoid-global-variables。
| 归档时间: |
|
| 查看次数: |
102 次 |
| 最近记录: |