我一直在用头撞墙,试图在 Julia 中使用静态数组。
https://github.com/JuliaArrays/StaticArrays.jl
它们速度很快,但更新它们很痛苦。这并不奇怪,它们注定是不可变的!
但不断有人建议我使用静态数组,即使我必须更新它们。在我的例子中,静态数组很小,只有 3 个长度,我有一个向量,但我一次只更新 1 个长度的三个向量。
选项1
有一个非常简洁的包叫做Setfield,它允许你在 Julia 中对 SVectors 进行就地更新。
https://github.com/jw3126/Setfield.jl
问题...它更新了本地副本。因此,如果您在嵌套函数中,它会更新本地副本。因此,它带有一些簿记,因为您必须就地更新本地副本,然后return该副本并更新实际感兴趣的数组。你不能传入你想要的数组并更新它,至少,我不能弄清楚!现在,我不介意簿记,但我觉得更新本地副本,然后返回值,更新另一个本地副本,然后返回值,最后更新实际数组必须带来速度损失。我可能是错的。
选项 2
让我感到困扰的是,为了更新静态数组,我必须
exampleSVector::SVector{3,Float64}<-- 只是为了明确它的类型和大小
exampleSVector = [value1, value2, value3]
这将更新所需的数组,即使它在函数内部,这很好,也是目标,但如果你在函数内部执行此操作,它会创建一个临时数组。这要了我的命,因为我的函数处于一个被调用 4+ 百万次的循环中,所以这会产生大量的分配并减慢速度。
如何在SVector不创建临时数组的情况下更新选项 2 场景?
对于选项 1 场景,我可以更新实际感兴趣的数组而不是本地副本吗?
如果这需要一个简单的示例代码,请在评论中说明,我会做一个。我的想法是没有一个是可以回答的,但是如果需要的话我会做一个。
编辑:
MCVE 代码 - 选项 1 有效,选项 2 无效。
using Setfield
using StaticArrays
struct Keep
dreaming::Vector{SVector{3,Float64}}
end
function INNER!(vec::SVector{3,Float64},pre::SVector{3,Float64})
# pretend series of calculations
for i = 1:3 # illustrate use of Setfield (used in real code for this)
pre = @set pre[i] = rand() * i * 1000
end
# more pretend calculations
x = 25.0 # assume more calculations equals x
################## OPTION 1 ########################
vec = @set vec = x * [ pre[1], pre[2], pre[3] ] # UNCOMMENT FOR FOR OPTION 1
return vec # UNCOMMENT FOR FOR OPTION 1
################## OPTION 2 ########################
#vec = x * [ pre[1], pre[2], pre[3] ] # UNCOMMENT FOR FOR OPTION 2
#nothing # UNCOMMENT FOR FOR OPTION 2
end
function OUTER!(always::Keep)
preAllocate = SVector{3}(0.0,0.0,0.0)
for i=1:length(always.dreaming)
always.dreaming[i] = INNER!(always.dreaming[i], preAllocate) # UNCOMMENT FOR FOR OPTION 1
#INNER!(always.dreaming[i], preAllocate) # UNCOMMENT FOR FOR OPTION 2
end
end
code = Keep([zero(SVector{3}) for i=1:5])
OUTER!(code)
println(code.dreaming)