Распределение массива при закрытии Юлии - PullRequest
0 голосов
/ 29 августа 2018

Интересно, стоит ли выделять временные массивы в let-блоке, что оборачивает какую-то функцию? Пример игрушки: вместо

function foo(x)
    y = zeros(100)
    for i in 1 : 100
        y[i] = 2*x[i] - 1
    end
    do_something(y)
end

Я напишу что-то вроде:

let
  const y = zeros(100) # otherwise foo will be type-unstable due to 'global' y
  function foo(x)
    for i in 1 : 100
        y[i] = 2*x[i] - 1
    end
    do_something(y)
  end
end

С помощью макроса @benchmark можно легко проверить, что во втором случае память для y-массива будет выделена только один раз, что значительно повышает производительность (в моем случае, не являющемся игрушкой). Мне интересно, это "юлианский" способ делать такие вещи?

1 Ответ

0 голосов
/ 29 августа 2018

Я дам вам ответ на Юлию 1.0. Для более ранних версий Юлии ситуация была бы несколько иной.

Пункт 1. Ваш код с let не будет работать под Julia 1.0, так как let создает локальную область, а в локальной области вы не можете использовать const.

Пункт 2. Вполне нормально сделать что-то подобное в глобальной области видимости:

const y = zeros(100) # otherwise foo will be type-unstable due to 'global' y
function foo(x)
    for i in 1 : 100
        y[i] = 2*x[i] - 1
    end
    do_something(y)
end

и у вас будет хорошая производительность, так как Julia 1.0 знает, что y имеет постоянный тип, и оптимизирует его. В результате у вас будет y в глобальной области видимости и foo в таблице методов (т. Е. Вы можете вызвать foo, используя его имя).

Пункт 3. Вы также можете использовать блок let следующим образом:

const foo = let y = zeros(100)
    function inner_foo(x)
        for i in 1 : 100
            y[i] = 2*x[i] - 1
        end
        do_something(y)
    end
end

На этот раз y определяется только в локальной области и не проникает в глобальную область. Также inner_foo не определено в глобальной области видимости, поэтому вы должны присвоить возвращаемое значение блока let переменной foo, которая затем может быть использована для выполнения вызовов (я делаю это const для повышения производительности, если оно будет использовано в некоторых функциях позже)

Пункт 4. Учтите, однако, что этот почти идентичный код будет не таким хорошим, поскольку у Julia 1.0 есть проблемы с выводом типа переменной y (надеюсь, это будет исправлено в будущем)

const foo = let
    y = zeros(100)
    function inner_foo(x)
        for i in 1 : 100
            y[i] = 2*x[i] - 1
        end
        do_something(y)
    end
end

В итоге: решение о том, что вы используете блок let, зависит главным образом от того, что вы должны видеть в области видимости global (поскольку то, что определено в let, не отображается в глобальной области видимости) и если вы используете * Блок 1034 * лучше всего определить переменные, которые вы хотите использовать как часть определения блока let.

...