带Type参数的多分派函数与普通函数性能是否相当?
带
::Type{Algo1}参数的多分派函数调用是否与普通函数执行速度相当? 注意: 答案并非如此简单,请查看下方更新内容
我希望使用多分派版本来优化代码结构,但担心其执行速度会变慢?
普通版本
algo1_Init() = 0.0 @inline algo1_update(state) = state + 1.0 # should be very fast fit1(Init, update) = begin state = Init() for _ in 1:1e6 state = update(state) # very heavy loop end state end fit1(algo1_Init, algo1_update)
多分派版本
struct Algo1 end Init(::Type{Algo1}) = 0.0 @inline update(::Type{Algo1}, state) = state + 1.0 # should be very fast fit2(T) = begin state = Init(T) for _ in 1:1e6 state = update(T, state) # very heavy loop end state end fit2(Algo1)
更新内容
测试结果显示二者性能并非始终一致,多分派版本的速度约为普通版本的1/1.5。此外还有两个意外的无关发现:
- a) 数组中的
missing值会使计算速度降低10倍,详见代码中的CHANGE2; - b) 返回两个值比返回一个值慢10倍,详见代码中的
CHANGE1。
基准测试代码
using Distributions, BenchmarkTools struct SimpleVol end @inline predict(::Type{SimpleVol}, Q, prev, r) = begin d = r - Q.μ y = sqrt(d*d + 1e-6) v = Q.α*y + (1-Q.α)*prev.v (; v), 0.0 # (; v) # CHANGE1 end @inline predict_explicit(Q, prev, r) = begin d = r - Q.μ y = sqrt(d*d + 1e-6) v = Q.α*y + (1-Q.α)*prev.v (; v), 0.0 # (; v) # CHANGE1 end vol_llh_multi(T, Q, rs) = begin n = length(rs) l = findfirst(!ismissing, rs) state = (; v=abs(rs[l])) for t in max(l, 2):n rs[t] === missing && continue state, _ = predict(T, Q, state, rs[t]) # state = predict(T, Q, state, rs[t]) # CHANGE1 end end; vol_llh_explicit(T, Q, rs) = begin n = length(rs) l = findfirst(!ismissing, rs) state = (; v=abs(rs[l])) for t in max(l, 2):n rs[t] === missing && continue state, _ = predict_explicit(Q, state, rs[l]) # state = predict_explicit(Q, state, rs[l]) # CHANGE1 end end; returns = rand(Normal(0, 0.015), 10_000); isweekend(i) = (mod(i,7) == 6) || (mod(i,7) == 0); returns2 = [isweekend(i) ? missing : returns[i] for i in 1:length(returns)]; # Warmup vol_llh_explicit(SimpleVol, (α = 0.048, μ = 0.0004, ν = 4.203), returns2) vol_llh_multi(SimpleVol, (α = 0.048, μ = 0.0004, ν = 4.203), returns2) # Bench println("Explicit Method") @benchmark vol_llh_explicit(SimpleVol, (α = 0.048, μ = 0.0004, ν = 4.203), returns2) println("Multi Method") @benchmark vol_llh_multi(SimpleVol, (α = 0.048, μ = 0.0004, ν = 4.203), returns2) # CHANGE2 use returns instead of returns2 in benchmark
内容的提问来源于stack exchange,提问作者Alex Craft
相关产品推荐
相关产品推荐

