我进行了一些关于从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})
现在有一个简单的愚蠢基准测试功能,它尝试从ets表中多次选择test_string,并测量每个选择的时间:
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表中进行选择有时会导致这样的放慢,或者如何对其进行性能分析。
更新:这里是时间分布图: