我打算从下面这个代码开始(我的学科相空间的演化过程),
restenergy = 0.511e6 # 电子静止质量[eV]
nturns = 100000
v1 = 3.6395053705870048e+06
r = 0.1801760487622639
ϕs = 2.1575815005097385
ϕ2s = 6.0620746573056303
h1 = 756
h = 3
circum = 1360.4
centerenergy = 6e9
αc = 0.0000156
@time begin
zvecs = []; δvecs = [] # 这两个用来保存相空间演化的历史数据
for i = 1:nturns
δvec .= δvec .+ v1 .* (sin.(ϕs .- 2 * h1 * π .* zvec ./ circum) .- sin(ϕs) .+ r .* sin.(ϕ2s .- 2 * h1 * h * π .* zvec ./ circum) .- r * sin(ϕ2s)) ./ centerenergy ./ circum
ηvec = αc .- 1 ./ (centerenergy .* (1 .+ δvec) ./ restenergy).^2
zvec .= zvec .- ηvec .* δvec
push!(zvecs, zvec)
push!(δvecs, δvec)
end
end
分三个视频快速讲讲大致怎么提高计算性能:
- 针对IO的优化(上面这种算I/O密集型吧)
1.1 数组内存预分配——用zeros()
去提前分配zvec,δvec,ηvec
内存
1.2@.
代替.+
等等——这里出现了问题;
1.3 底层代码标量优先——改成for
循环形式,但是行在外列在内;
1.4 第一个index最快——改成行在内 - 针对编译的优化(上面的代码稍微修改,不保存历史数据,只导出最后结果,算CPU密集型吧)
2.1 包装成函数——看看函数编译的提升效果
2.2 编写类型稳定的函数——δvec
用Vector{Int64}
类型,算着算着,变Vector{Float64}
类型
2.3 分离核心函数——循环调用的部分提取成函数
2.4 宏——for
循环加@inbounds
,@simd
2.5 全局变量的常数声明——之前的函数编译时,全局变量电子静止质量restenergy
没有指定为常数。加const
期望看到速度提高 - 针对CPU的优化
3.1 多线程——Threads.@spawn
,@sync
的使用
上面这个我选的例题和这个目录安排,各位有什么建议吗?
再来说说遇到的问题。下面这个代码,用@.
但是速度比上面慢。
@time begin
zvecs = []
δvecs = []
for i = 1:nturns
@. δvec = δvec + v1 * (sin(ϕs - 2 * h1 * π * zvec / circum) - sin(ϕs) + r * sin(ϕ2s - 2 * h1 * h * π * zvec / circum) - r * sin(ϕ2s)) / centerenergy / circum
ηvec = @. αc - 1 / (centerenergy * (1 + δvec) / restenergy)^2
@. zvec = zvec - ηvec * δvec
push!(zvecs, zvec)
push!(δvecs, δvec)
end
end
结果:43.634120 seconds (6.20 M allocations: 7.810 GiB, 1.48% gc time)
。
而上面: 31.876649 seconds (7.19 M allocations: 7.807 GiB, 2.32% gc time, 1.09% compilation time)
。
我猜测,这个例子,@.
没有带来好的效果,是由于.+
,.*
编译了引起的。但是我没有包装到函数里,怎么会编译呢?