考虑以下示例:
module structs
mutable struct testStruct
x::Array{Int64,2}
end
end
function innerFunc(s::structs.testStruct)
s.x[1:2] .= s.x[3:4]
end
function structTest!(s::structs.testStruct, n)
for i = 1:n
innerFunc(s)
end
println(s.x)
end
随着我增加n
,内存分配也会增加。我认为这是因为在每次迭代中,我都在为s.x[3:4]
创建分配。我可以通过使用循环来避免这种情况:
function innerFunc(s::structs.testStruct)
for i = 1:2
s.x[i] .= s.x[i+2]
end
end
function structTest!(s::structs.testStruct, n)
for i = 1:n
innerFunc(s)
end
println(s.x)
end
但是,我不喜欢循环,因为语法很麻烦。有没有办法避免它?在每次迭代中,我想修改s.x
的第一个和第二个元素而不增加内存分配,因为我增加了n
,因为我没有创建任何新内容。
更新:为了回应DNF,我尝试使用@view
:
module structs
mutable struct testStruct
x::Array{Int64,2}
end
end
function innerfunc!(s::structs.testStruct)
s.x[1:2] .= view(s.x, 3:4)
end
function structTest!(s::structs.testStruct, n)
for i = 1:n
innerfunc!(s)
end
println(s.x)
end
这就是我得到的:
@time structTest!(structs.testStruct([1 2 3 4]),33)
0.000112 seconds (202 allocations: 7.938 KiB)
@time structTest!(structs.testStruct([1 2 3 4]),330)
0.000126 seconds (1.69 k allocations: 68.266 KiB)
我希望分配对n
保持不变。
答案 0 :(得分:2)
使用view
:
function innerfunc!(s::structs.testStruct)
s.x[1:2] .= view(s.x, 3:4)
end
或
function innerfunc!(s::structs.testStruct)
@views s.x[1:2] .= s.x[3:4]
end
哦,并在函数名中添加!
,因为它会改变输入。
编辑:显然,我错了。视图做分配一点点。但是你做基准测试的方式会给你非常错误的答案,特别是当你在全球范围内进行基准测试时,内存估计是偏离的。一些提示:
x::Array{Int, 1}
或x::Vector{Int}
代替Array{Int, 2}
。print
语句!即
struct TestStruct
x::Vector{Int64}
end
function innerfunc!(s::TestStruct)
s.x[1:2] .= view(s.x, 3:4)
end
function structtest!(s::TestStruct, n)
for i = 1:n
innerfunc!(s)
end
return s
end
julia> s = TestStruct([1, 2, 3, 4])
TestStruct([1, 2, 3, 4])
julia> @btime structtest!($s, 33)
575.108 ns (33 allocations: 1.55 KiB)
TestStruct([3, 4, 3, 4])
答案 1 :(得分:2)
正如@DNF所指出的,使用视图应该已经解决了问题,但由于视图不是不可变的,因此存储器成本很低,这在通常的应用程序中并不重要。
基本上,你必须使用for
循环。为了让它看起来有点矢量化,Dahua Lin的Devectorized.jl软件包得以拯救:
# Pkg.add("Devectorized.jl")
using Devectorized
function innerfunc!(s::structs.testStruct)
@devec s.x[1:2] = s.x[3:4]
end
你很高兴:
julia> @time structTest!(structs.testStruct([1 2 3 4]),3300)
0.000299 seconds (40 allocations: 1.641 KiB)
julia> @time structTest!(structs.testStruct([1 2 3 4]),330000)
0.001209 seconds (40 allocations: 1.641 KiB)