为什么这个简单的索引变量在 Julia 中被 gettng Box-ed?
Why is this simple indexing variable gettng Box-ed in Julia?
在从 Project Euler 手动求解 Problem 10 时(而不是简单地 using Primes
),我使用 BitVector
在 Julia 中实现了一个朴素的埃拉托色尼筛法。它产生了正确的输出,但是当我使用 @code_warntype
检查其类型稳定性时,我发现 i
被分配为 Core.Box
,这会影响 psum
的类型,并且这反过来又会破坏整个函数的类型稳定性。这是使用的代码:
function primesum(limit::T = 2_000_000) where T<:Integer
#easy way: using Primes; sum(primes(limit))
#hard way:
is_prime_num = BitVector(limit)
is_prime_num .= true
psum = zero(limit)
for i in 2:limit
if is_prime_num[i]
psum += i
multiples_of_i = [k*i for k in 2:(limit÷i)]
is_prime_num[multiples_of_i] .= false
end
end
psum
end
这里是 code_warntype
输出的变量部分(完整输出 here):
Variables:
#self#::#primesum
limit::Int64
#46::##46#47
i::Core.Box
multiples_of_i::Any
#temp#@_6::Int64
is_prime_num::BitArray{1}
psum::Any
J::Any
#temp#@_10::Any
总的来说,代码中的很多类型(包括函数的 return 类型)都保留为 Any
或 where _
类型。
我能够通过将 for
循环行更改为 for i::T in 2:limit
来提高速度(几乎 10 倍)和内存(~3 倍)- 然后,i
仍然被设置为Core.Box
,但这得到 typeassert
ed 到 Int64 并且不会将不稳定性传播到 psum
和其他人。但是 我更感兴趣的是为什么 Julia 不能推断 i
的类型而不是加速这个特定的代码。 我习惯于输入不稳定性至少是有意义的回想起来,但这一个似乎非常清晰且易于推断,所以我想知道这里哪里存在类型歧义。
一个临时解决方案是将 i
包装在 let
块中围绕理解(我还建议对您的代码进行一些小的调整,这些调整是较小的清理 - 我已经创建了 multiples_of_i
因为这是你问题的核心但实际上使用这个变量也是低效的 - 最好使用循环在适当的地方将 is_prime_num
向量设置为 false
):
function primesum(limit::Integer = 2_000_000)
is_prime_num = trues(limit)
psum = zero(limit)
for i in 2:limit
if is_prime_num[i]
psum += i
let i=i
multiples_of_i = [k*i for k in 2:(limit÷i)]
is_prime_num[multiples_of_i] .= false
end
end
end
psum
end
希望在长期 运行 中,问题 https://github.com/JuliaLang/julia/issues/15276 将得到解决,这将不再需要。
在从 Project Euler 手动求解 Problem 10 时(而不是简单地 using Primes
),我使用 BitVector
在 Julia 中实现了一个朴素的埃拉托色尼筛法。它产生了正确的输出,但是当我使用 @code_warntype
检查其类型稳定性时,我发现 i
被分配为 Core.Box
,这会影响 psum
的类型,并且这反过来又会破坏整个函数的类型稳定性。这是使用的代码:
function primesum(limit::T = 2_000_000) where T<:Integer
#easy way: using Primes; sum(primes(limit))
#hard way:
is_prime_num = BitVector(limit)
is_prime_num .= true
psum = zero(limit)
for i in 2:limit
if is_prime_num[i]
psum += i
multiples_of_i = [k*i for k in 2:(limit÷i)]
is_prime_num[multiples_of_i] .= false
end
end
psum
end
这里是 code_warntype
输出的变量部分(完整输出 here):
Variables:
#self#::#primesum
limit::Int64
#46::##46#47
i::Core.Box
multiples_of_i::Any
#temp#@_6::Int64
is_prime_num::BitArray{1}
psum::Any
J::Any
#temp#@_10::Any
总的来说,代码中的很多类型(包括函数的 return 类型)都保留为 Any
或 where _
类型。
我能够通过将 for
循环行更改为 for i::T in 2:limit
来提高速度(几乎 10 倍)和内存(~3 倍)- 然后,i
仍然被设置为Core.Box
,但这得到 typeassert
ed 到 Int64 并且不会将不稳定性传播到 psum
和其他人。但是 我更感兴趣的是为什么 Julia 不能推断 i
的类型而不是加速这个特定的代码。 我习惯于输入不稳定性至少是有意义的回想起来,但这一个似乎非常清晰且易于推断,所以我想知道这里哪里存在类型歧义。
一个临时解决方案是将 i
包装在 let
块中围绕理解(我还建议对您的代码进行一些小的调整,这些调整是较小的清理 - 我已经创建了 multiples_of_i
因为这是你问题的核心但实际上使用这个变量也是低效的 - 最好使用循环在适当的地方将 is_prime_num
向量设置为 false
):
function primesum(limit::Integer = 2_000_000)
is_prime_num = trues(limit)
psum = zero(limit)
for i in 2:limit
if is_prime_num[i]
psum += i
let i=i
multiples_of_i = [k*i for k in 2:(limit÷i)]
is_prime_num[multiples_of_i] .= false
end
end
end
psum
end
希望在长期 运行 中,问题 https://github.com/JuliaLang/julia/issues/15276 将得到解决,这将不再需要。