Телерадиовещание медленное Юлия - PullRequest
3 голосов
/ 11 марта 2020

У меня есть что-то вроде этого (простой пример):

using BenchmarkTools
function assign()
    e = zeros(100, 90000)
    e2 = ones(100) * 0.16
    e[:, 100:end] .= e2[:]
end
@benchmark assign()

, и мне нужно это для тысяч временных шагов. Это дает

BenchmarkTools.Trial: 
  memory estimate:  68.67 MiB
  allocs estimate:  6
  --------------
  minimum time:     16.080 ms (0.00% GC)
  median time:      27.811 ms (0.00% GC)
  mean time:        31.822 ms (12.31% GC)
  maximum time:     43.439 ms (27.66% GC)
  --------------
  samples:          158
  evals/sample:     1

Есть ли более быстрый способ сделать это?

1 Ответ

8 голосов
/ 11 марта 2020

Прежде всего, я предполагаю, что вы имели в виду

function assign1()
    e = zeros(100, 90000)
    e2 = ones(100) * 0.16
    e[:, 100:end] .= e2[:]
    return e  # <- important!
end

Поскольку в противном случае вы не вернете первые 99 столбцов e (!):

julia> size(assign())
(100, 89901)

Во-вторых, не делайте этого:

e[:, 100:end] .= e2[:]

e2[:] делает копию e2 и назначает ее, но почему? Просто назначьте e2 напрямую:

e[:, 100:end] .= e2

Хорошо, но давайте попробуем несколько разных версий. Обратите внимание, что нет необходимости делать e2 вектором, просто назначьте скаляр:

function assign2()
    e = zeros(100, 90000)
    e[:, 100:end] .= 0.16  # Just broadcast a scalar!
    return e
end

function assign3()
    e = fill(0.16, 100, 90000)  # use fill instead of writing all those zeros that you will throw away
    e[:, 1:99] .= 0
    return e
end

function assign4()
    # only write exactly the values you need!
    e = Matrix{Float64}(undef, 100, 90000)
    e[:, 1:99] .= 0
    e[:, 100:end] .= 0.16
    return e
end

Время для сравнения

julia> @btime assign1();
  14.550 ms (5 allocations: 68.67 MiB)

julia> @btime assign2();
  14.481 ms (2 allocations: 68.66 MiB)

julia> @btime assign3();
  9.636 ms (2 allocations: 68.66 MiB)

julia> @btime assign4();
  10.062 ms (2 allocations: 68.66 MiB)

Версии 1 и 2 одинаково быстры, но вы Заметим, что есть 2 распределения вместо 5, но, конечно, доминирует большое распределение.

Версии 3 и 4 быстрее, но не так драматично, но вы видите, что это избегает некоторой дублирующей работы, такой как как запись значений в матрицу дважды. Версия 3 самая быстрая, но не намного, но она меняется, если назначение немного более сбалансировано, и в этом случае версия 4 быстрее:

function assign3_()
    e = fill(0.16, 100, 90000)
    e[:, 1:44999] .= 0
    return e
end

function assign4_()
    e = Matrix{Float64}(undef, 100, 90000)
    e[:, 1:44999] .= 0
    e[:, 45000:end] .= 0.16
    return e
end

julia> @btime assign3_();
  11.576 ms (2 allocations: 68.66 MiB)

julia> @btime assign4_();
  8.658 ms (2 allocations: 68.66 MiB)

Урок состоит в том, чтобы избегать ненужной работы.

...