Проблема этой функции в том, что у компилятора Julia возникают проблемы с выводом типа, когда в вашей функции появляются замыкания.В этом случае замыкание является пониманием, и проблема в том, что оператор if
делает sieve
определяемым только условно.
Это можно увидеть, сдвинув sieve
вверх:
function get_primes_1(n::Int64, s::Int64=2)::Vector{Int64}
sieve = fill(true, n)
if n <= 1 || s > n
return Int[]
end
for i = 3:2:isqrt(n) + 1
if sieve[i]
for j = i ^ 2:i:n
sieve[j]= false
end
end
end
pl = [i for i in s - s % 2 + 1:2:n if sieve[i]]
return s == 2 ? unshift!(pl, 2) : pl
end
Однако, это делает sieve
созданным также, когда n<1
, которого вы хотите избежать, я думаю:).
Вы можете решить эту проблему, обернув sieve
в let
блок какэто:
function get_primes_1(n::Int64, s::Int64=2)::Vector{Int64}
if n <= 1 || s > n
return Int[]
end
sieve = fill(true, n)
for i = 3:2:isqrt(n) + 1
if sieve[i]
for j = i ^ 2:i:n
sieve[j]= false
end
end
end
let sieve = sieve
pl = [i for i in s - s % 2 + 1:2:n if sieve[i]]
return s == 2 ? unshift!(pl, 2) : pl
end
end
или избегание внутреннего замыкания, например, вот так:
function get_primes_1(n::Int64, s::Int64=2)::Vector{Int64}
if n <= 1 || s > n
return Int[]
end
sieve = fill(true, n)
for i = 3:2:isqrt(n) + 1
if sieve[i]
for j = i ^ 2:i:n
sieve[j]= false
end
end
end
pl = Int[]
for i in s - s %2 +1:2:n
sieve[i] && push!(pl, i)
end
s == 2 ? unshift!(pl, 2) : pl
end
Теперь вы можете спросить, как вы можете обнаружить такие проблемы и убедиться, что какое-то решение их решает?Ответ заключается в использовании @code_warntype
для функции.В исходной функции вы заметите, что sieve
- это Core.Box
, что является признаком проблемы.
Подробнее см. https://github.com/JuliaLang/julia/issues/15276.В целом, на мой взгляд, это самая важная проблема с производительностью кода Джулии, которую легко не заметить.Надеюсь, что в будущем компилятор будет умнее с этим.