Est*_*ban 6 constructor constants julia
我很确定这必须是一个bug ...
好吧,基本上,当我将一个Math Constant类型传递给power(^)函数并多次迭代时......循环非常慢并且使用了大量的内存分配.这个例子是微不足道的,因为它不会产生任何结果,但我有真正的应用程序,我有这个问题.
function test1(N)
for i = 1:N
x = pi^4
end
end
function test2(N)
for i = 1:N
x = pi*pi*pi*pi
end
end
function test3(N)
pif = float64(pi)
for i = 1:N
x = pif^4
end
end
Run Code Online (Sandbox Code Playgroud)
这是用大N调用函数的结果:
@time test1(10000000)
@time test2(10000000)
@time test3(10000000)
elapsed time: 0.958278949 seconds (320000160 bytes allocated, 56.44% gc time)
elapsed time: 6.341e-6 seconds (80 bytes allocated)
elapsed time: 4.982e-6 seconds (80 bytes allocated)
Run Code Online (Sandbox Code Playgroud)
这是一个错误吗?或者它有合理的解释吗?在大循环中为pi提供动力的正确方法是什么?
谢谢.
虽然看起来您使用的是 Julia 0.3,并且这些结果主要与 Julia 0.4 有关,但它也存在相同的问题,原因相同,都是不必要的中间体分配。
要了解发生了什么,您可以键入methods(^),它将生成为实现 ^ 定义的所有方法的列表。它们有很多,所以我不会列出它们,但重要的是列出了实现它们的 Julia 文件,在本例中,它是Constants.jl。
第一次在朱莉娅0.3
julia> @time test1(10000000)
elapsed time: 0.313772825 seconds (320393016 bytes allocated, 37.16% gc time)
Run Code Online (Sandbox Code Playgroud)
在 Julia 0.4 中,由于有了更好的垃圾收集器,这个问题有所减少,但仍然存在。
julia> @time test1(10000000)
170.445 milliseconds (20000 k allocations: 305 MB, 6.94% gc time)
julia> @time test2(10000000)
2.355 microseconds (4 allocations: 144 bytes)
Run Code Online (Sandbox Code Playgroud)
当分配数量异常时,始终怀疑类型不稳定或临时性。
特别地,第 70 行到第 72 行定义了用于对 MathConst 求幂的通用方法。
for op in Symbol[:+, :-, :*, :/, :^]
@eval $op(x::MathConst, y::MathConst) = $op(Float64(x),Float64(y))
end
Run Code Online (Sandbox Code Playgroud)
另请注意,稍后是常量 e 的专门化,并且将 pi 替换为 e 的新测试不会出现同样的问题。
julia> function test4(N)
for i = 1:N
x = e^4
end
end
test4 (generic function with 1 method)
Run Code Online (Sandbox Code Playgroud)
运行测试4
julia> @time test4(10000000)
108.401 milliseconds (4 allocations: 144 bytes)
Run Code Online (Sandbox Code Playgroud)
如果从Int创建Float ,那么从Float开始可以避免该问题。
julia> function test5(N)
for i = 1:N
x = pi^4.0
end
end
Run Code Online (Sandbox Code Playgroud)
这就是发生的事情
julia> @time test5(10000000)
65.430 milliseconds (4 allocations: 144 bytes)
Run Code Online (Sandbox Code Playgroud)
最后,可以创建一组新函数(在本例中进行测试),专门将 Int 定义为第二个参数以避免强制转换。这不是最好的方法,因为它引入了歧义,但它适合测试。
julia> for op in Symbol[:+, :-, :*, :/, :^]
@eval $op(x::MathConst, y::Int64) = $op(Float64(x),y)
end
Warning: New definition
^(MathConst{sym}, Int64) at none:2
is ambiguous with:
^(MathConst{:e}, Integer) at constants.jl:122.
To fix, define
^(MathConst{:e}, Int64)
before the new definition.
Run Code Online (Sandbox Code Playgroud)
julia> function test1(N)
for i = 1:N
x = pi^4
end
end
test1 (generic function with 1 method)
Run Code Online (Sandbox Code Playgroud)
然后重新运行
julia> @time test1(10000000)
2.757 microseconds (4 allocations: 144 bytes)
Run Code Online (Sandbox Code Playgroud)
相同的修复,但使用float64而不是Float64
julia> for op in Symbol[:+, :-, :*, :/, :^]
@eval $op(x::MathConst, y::Int64) = $op(float64(x),y)
end
Run Code Online (Sandbox Code Playgroud)
最后在 Julia 0.3 中重新定义并重新运行测试
julia> @time test1(10000000)
elapsed time: 3.023e-6 seconds (80 bytes allocated)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
290 次 |
| 最近记录: |