AFAIK, ets:lookup_element/3
is most effect ets
function and if you don’t have any bottlenecks about lock compete, IMO, maybe you have to use something to instead of ets.
If you never change these data after insert, maybe you can try persistent_term
a simple test
erl -noshell -eval “test:run(100000, 1000),init:stop().”
-module(test).
-compile([export_all, nowarn_export_all]).
run(DataSize, LookupSize) ->
%% init
ets:new(test_binary, [named_table]),
ets:new(test_int, [named_table]),
PId =
spawn(fun() ->
M = lists:foldl(fun(N, Acc) -> Acc#{N => N} end, #{}, lists:seq(1, DataSize)),
receive
{From, KeyL} ->
From ! [maps:get(Key, M) || Key <- KeyL]
end
end),
lists:foreach(fun(N) ->
ets:insert(test_int, {N, N}),
%% i don't know the detail about these binary
ets:insert(test_binary, {<<N:32, N:32>>, <<N:32, N:32>>})
end, lists:seq(1, DataSize)),
%% int
SeqLookupInt = lists:seq(1, LookupSize),
{IntTime, _} = timer:tc(fun() -> [ ets:lookup_element(test_int, Key, 2) || Key <- SeqLookupInt ] end),
%% binary
SeqLookupBinary = [ <<N:32, N:32>> || N <- SeqLookupInt],
{BinaryTime, _} = timer:tc(fun() -> [ ets:lookup_element(test_binary, Key, 2) || Key <- SeqLookupBinary ] end),
%% process
{ProcessTime, _} = timer:tc(fun() -> PId ! {self(), SeqLookupInt}, receive Value -> Value end end),
io:format("data size: ~p, lookup size: ~p, int cost: ~p, bianry cost: ~p~n, process cost: ~p",
[DataSize, LookupSize, IntTime, BinaryTime, ProcessTime]).