我想出了两种方法来在一对复合类型中添加所有数组.第一种方式(add_structs_1)需要4秒才能运行,第二种方式(add_structs_2)需要0.15秒.但第二种方法需要更多代码......我必须明确提到复合类型中的每个字段.有没有办法在add_structs_2不明确列出每个字段的情况下获得效率?
type SampleStruct
a::Vector{Float64}
k::Matrix{Float64}
e_axis::Vector{Float64}
e_dev::Vector{Float64}
e_scale::Vector{Float64}
end
function add_structs_1(tgt::SampleStruct, src::SampleStruct)
for n in names(SampleStruct)
for i in 1:length(tgt.(n))
tgt.(n)[i] += src.(n)[i]
end
end
end
function add_structs_2(tgt::SampleStruct, src::SampleStruct)
for i in 1:length(tgt.a)
tgt.a[i] += src.a[i]
end
for i in 1:length(tgt.k)
tgt.k[i] += src.k[i]
end
for i in 1:length(tgt.e_axis)
tgt.e_axis[i] += src.e_axis[i]
end
for i in 1:length(tgt.e_dev)
tgt.e_dev[i] += src.e_dev[i]
end
for i in 1:length(tgt.e_scale)
tgt.e_scale[i] += src.e_scale[i]
end
end
function time_add_structs(f::Function)
src = SampleStruct(ones(3), ones(3,3), [1.], [1.], [1.])
tgt = SampleStruct(ones(3), ones(3,3), [1.], [1.], [1.])
@time for i in 1:1000000
f(tgt, src)
end
end
time_add_structs(add_structs_1)
time_add_structs(add_structs_1)
time_add_structs(add_structs_2)
time_add_structs(add_structs_2)
time_add_structs(add_structs_3)
time_add_structs(add_structs_3)
Run Code Online (Sandbox Code Playgroud)
更为朱利安的方法add_structs_1是使内部循环成为一个单独的函数,这允许编译器专门化每个类型的函数SampleStruct并提供相当快的速度.
通过分析代码,可以看出执行的时间names(SampleStruct)非常重要,这应该在你的基准测试的每次迭代中完成,通过使它成为一个全局常量获得一些时间并且函数现在看起来像:
function add_array(a::AbstractArray,b::AbstractArray)
for i in 1:length(a)
a[i] += b[i]
end
end
const names_in_struct = names(SampleStruct)
function add_structs_3(tgt::SampleStruct, src::SampleStruct)
for n in names_in_struct
add_array(tgt.(n),src.(n))
end
end
Run Code Online (Sandbox Code Playgroud)
该功能现在只有四分之一 add_structs_2
元编程方法更复杂,但性能相同 add_structs_2
ex = Any[]
for n in names(SampleStruct)
t = Expr(:.,:tgt, QuoteNode(n))
s = Expr(:.,:src, QuoteNode(n))
e=quote
for i in 1:length($t)
$t[i] += $s[i]
end
end
push!(ex,e)
end
eval(quote function add_structs_4(tgt::SampleStruct, src::SampleStruct)
$(Expr(:block,ex...))
end
end)
Run Code Online (Sandbox Code Playgroud)