在复合类型中添加所有数组的高效且简洁的方法?

Jef*_*eff 2 julia

我想出了两种方法来在一对复合类型中添加所有数组.第一种方式(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)

Dan*_*egh 5

更为朱利安的方法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)