Ответ 1
Так забавно, что нужно использовать @code_warntype
в Julia 0.4, который показывает следующее:
julia> @code_warntype g1(10, f)
Variables:
N::Int64
fIn::F
z::Any
#s1::Int64
n::Int64
Body:
begin # none, line 2:
z = 0 # line 3:
... snip ....
z = z + (fIn::F)(n::Int64,n::Int64)::Any::Any
Таким образом, проблема заключается в выводе типа возврата f
, который действительно может быть чем угодно. Проблема (как я понимаю) заключается в том, что Julia компилирует метод для каждой комбинации типов. У нас есть код, созданный здесь для любой функции, поэтому все может вернуться. Было бы аккуратно, если Function
был параметрическим по типу возврата, потому что тогда мы могли бы сделать что-то умнее, чем Function{T<:Any,Int}
.
Мое решение состояло в том, чтобы изменить его на z += fIn(n, n)::Int
, и это позволяет z
всегда быть Int
, но я все еще вижу
(top(typeassert))((fIn::F)(n::Int64,n::Int64)::Any,Int)::Int64
в выводе @code_warntype
, что имеет смысл, потому что он по-прежнему остается Any
, я просто уверен, что это не загрязняет остальных. Но я думаю, что он все равно должен генерировать код, чтобы проверить, что это на самом деле Int
. Позволяет называть эту новую версию g1A
:
julia> @time g1(1000000, f)
elapsed time: 0.124437357 seconds (30 MB allocated, 2.82% gc time in 1 pauses with 0 full sweep)
elapsed time: 0.121653131 seconds (30 MB allocated, 2.51% gc time in 2 pauses with 0 full sweep)
elapsed time: 0.120805345 seconds (30 MB allocated, 1.17% gc time in 1 pauses with 0 full sweep)
julia> @time g1A(1000000, f)
elapsed time: 0.085875439 seconds (30 MB allocated, 5.20% gc time in 1 pauses with 0 full sweep)
elapsed time: 0.074592531 seconds (30 MB allocated, 4.67% gc time in 2 pauses with 0 full sweep)
elapsed time: 0.078681071 seconds (30 MB allocated, 4.75% gc time in 1 pauses with 0 full sweep)
Итак, некоторые выгоды, но не идеальные. Это известная проблема, которая углубляется во внутренние работы Юлии. Связанное обсуждение: