Я провел несколько тестов на предмет эффективности выбора из таблиц ets и заметил странное поведение. Например, у нас есть простая таблица ets (без каких-либо конкретных опций), в которой хранится ключ / значение - случайная строка и число:
:ets.new(:table, [:named_table])
for _i <- 1..2000 do
:ets.insert(:table, {:crypto.strong_rand_bytes(10)
|> Base.url_encode64
|> binary_part(0, 10), 100})
end
и одна запись с известным ключом:
:ets.insert(:table, {"test_string", 200})
Теперь есть простая глупая функция бенчмарка, которая пытается несколько раз выбрать test_string
из таблицы ets и измерить время каждого выбора:
test_fn = fn() ->
Enum.map(Enum.to_list(1..10_000), fn(x) ->
:timer.tc(fn() ->
:ets.select(:table, [{{:'$1', :'$2'},
[{:'==', :'$1', "test_string"}],
[:'$_']}])
end)
end) |> Enum.unzip
end
Теперь, если я посмотрю на максимальное время с помощью Enum.max(timings)
он вернет значение, которое примерно в 10 раз больше, чем почти все другие варианты выбора. Так, например:
iex(1)> {timings, _result} = test_fn.()
....
....
....
iex(2)> Enum.max(timings)
896
iex(3)> Enum.sum(timings) / length(timings)
96.8845
Здесь мы можем видеть, что максимальное значение почти в 10 раз превышает среднее значение.
Что здесь происходит? Это как-то связано с GC, временем для выделения памяти или чем-то вроде этого? Есть ли у вас какие-либо идеи, почему выборка из таблицы ets может иногда приводить к таким замедлениям или как ее профилировать?
UPD.
вот график распределения таймингов:![enter image description here](https://i.stack.imgur.com/NVqcJ.png)