Дополнительные выделения памяти при изменении типа кортежа

#julia

#julia

Вопрос:

С Julia 1.5.3 у меня есть следующий код (конечно, это не настоящий код, просто надуманный пример, с помощью которого я мог бы воспроизвести проблему):

 function basic()
    result::Tuple{Int64,Int64,Int64} = (0, 0, 0)
    for i in 1:100000
        for i in -1:1, j in -1:1, k in -1:1
            result = result .  (i, j, k)
        end
    end
    result
end

function fancy(T)
    result::T = (0, 0, 0)
    for i in 1:100000
        for i in -1:1, j in -1:1, k in -1:1
            result = result .  (i, j, k)::T
        end
    end
    result
end

# Warmup
for i in 1:10
    basic()
    fancy(Tuple{Int64,Int64,Int64})
end

println("basic:")
println(@time basic())
println("fancy:")
println(@time fancy(Tuple{Int64,Int64,Int64}))
 

выводит:

 basic:
  0.000000 seconds
(0, 0, 0)
fancy:
  0.762599 seconds (10.80 M allocations: 494.385 MiB, 3.68% gc time)
(0, 0, 0)
 

Если я напишу вместо:

             result = result .  (i, j, k)::T
 

Я получаю:

 basic:
  0.000000 seconds
(0, 0, 0)
fancy:
  0.789512 seconds (13.50 M allocations: 576.782 MiB, 3.77% gc time)
(0, 0, 0)
 

Есть ли способ сделать basic и fancy выполнить то же самое, т. Е. Без выделения fancy ?

Комментарии:

1. Вы также можете рассмотреть возможность использования SVector from StaticArrays вместо этого.

Ответ №1:

Просто измените подпись fancy :

 function fancy(::Type{T}) where T
    result::T = (0, 0, 0)
    for i in 1:100000
        for i in -1:1, j in -1:1, k in -1:1
            result = result .  (i, j, k)::T
        end
    end
    result
end

println(@time fancy(Tuple{Int64,Int64,Int64}))
 

Просто обратите внимание, что обе функции фактически оптимизированы для почти безоперационной работы. Вы можете проверить это с @code_native basic() помощью .

Комментарии:

1. Спасибо, это имеет смысл. На всякий случай, fancy(::Type{T}) where T означает, что мы принимаем параметр, который является типом, и этот тип параметризован как T. Итак, теперь мне любопытно, что сделал код в моем вопросе: function fancy(T) result::T = (0, 0, 0) ... что тогда было T?

2. Да, в моем вопросе T был параметр типа Any . Но тогда что это result::T значило? Я предполагаю, что это была динамическая проверка типа во время назначения?

3. ДА. На самом деле это больше похоже result = convert(T, (0,0,0)) , чем утверждение типа.

Ответ №2:

Как насчет этого?

 function fancy(T)
    result = T((0, 0, 0))
    for i in 1:100000
        for i in -1:1, j in -1:1, k in -1:1
            result = result .  T((i, j, k))
        end
    end
    result
end