julia - 以复合类型添加所有数组的高效而简洁的方法?

标签 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)

最佳答案

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

该函数现在是 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)

关于julia - 以复合类型添加所有数组的高效而简洁的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29856921/

相关文章:

statistics - Julia 的移动平均线

julia - 类似于 'SubArray' 但有多个父数组?

websocket - Julia - 如何通过 WebSockets 订阅

julia - 数字类型(函数返回 "wrong"结果)

julia - 如何在 julia/examples 中运行 plife.jl?

curl - 如何重用 curl_easy 连接?

fft - 计算导数傅立叶系数 Julia

python - 无法将 PyJulia 与 Julia 1.0 和 Conda Python 3.6 一起使用

filesystems - 检查文件夹是否存在

python - Julia 中 Python 的 ast.literal_eval() 相当于什么?