我想出了两种方法来在一对复合类型中添加所有数组。第一种方式(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)
答案 0 :(得分:5)
add_structs_1
的更多julian方法是使内循环成为一个单独的函数,这允许编译器专门化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
该功能现在是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)
答案 1 :(得分:4)
这些for循环中的每一个都可以用单行替换,使得长版本就是这样:
function add_structs_3(tgt::SampleStruct, src::SampleStruct)
tgt.a[:] += src.a
tgt.k[:,:] += src.k
tgt.e_axis[:] += src.e_axis
tgt.e_dev[:] += src.e_dev
tgt.e_scale[:] += src.e_scale
end
这与add_structs_1
的长度相同,但速度较慢,因为它实际上构建了一个临时数组,然后执行赋值。您还可以使用一些元编程来生成更长的代码。
答案 2 :(得分:1)
应该获得最佳案例的所有表现的方法是结合Daniel和Stefan的答案:将添加定义为单独的函数,就像在Daniel的解决方案中一样,而不是迭代在名单列表中,每个字段都像Stefan的回答一样手动。