Erlang mnesiaダーティリード性能テスト
8435 ワード
詳細
mnesiaには2つの方法でデータを汚い読み方があり、1つはKeyでdirty_read(Tab,Key)は、他のインデックスが確立されたフィールドでdirty_を読み出すindex_read(Tab, OtherKey, Position).最初はこの2つの速度が同じだと思っていたが、片側は1つ目が2つ目の3倍近く発見された.テストは1千万のデータ、10万のプロセスで同時アクセスします.
テスト用のコード:
tcのコード:
結果:10万同時プロセスでfindとfind 1にアクセスし、結果:
基本dirtyを何回か測定しましたreadは2マイクロ秒程度、dirty_index_readは7マイクロ秒程度です.性能は3倍程度.
まとめ:
テストの結果、mnesiaでデータをすばやく読み取りたい場合は、できるだけチェックしたフィールドをKeyとします.
mnesiaには2つの方法でデータを汚い読み方があり、1つはKeyでdirty_read(Tab,Key)は、他のインデックスが確立されたフィールドでdirty_を読み出すindex_read(Tab, OtherKey, Position).最初はこの2つの速度が同じだと思っていたが、片側は1つ目が2つ目の3倍近く発見された.テストは1千万のデータ、10万のプロセスで同時アクセスします.
テスト用のコード:
-module (tm).
-behaviour (gen_server).
% APIs
-export([start_link/0, find/1, find1/1, ct/0, ct1/0]).
% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-record (test_mnesia, {userid, pid}).
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
find(UserId) ->
mnesia:dirty_read(test_mnesia, UserId).
find1(UserId) ->
mnesia:dirty_index_read(test_mnesia, UserId, #test_mnesia.pid).
ct() ->
tc:ct(tm, find, [<>], 100000).
ct1() ->
tc:ct(tm, find1, [<>], 100000).
%% ===================================================================
%% gen_server callbacks
%% ===================================================================
init([]) ->
mnesia:stop(),
mnesia:delete_schema([node()]),
mnesia:create_schema([node()]),
mnesia:start(),
{atomic,ok} = mnesia:create_table(test_mnesia, [{ram_copies, [node()]},
{attributes, record_info(fields, test_mnesia)}]),
{atomic,ok} = mnesia:add_table_index(test_mnesia, pid),
loop(10000000),
{ok, []}.
handle_call(_Request, _From, State) ->
{reply, nomatch, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) -> ok.
code_change(_OldVer, State, _Extra) -> {ok, State}.
%% ===================================================================
%% Internal functions
%% ===================================================================
loop(N) when N > 0 ->
UserId = <>,
mnesia:dirty_write(#test_mnesia{userid = UserId, pid = UserId}),
loop(N - 1);
loop(0) ->
ok.
tcのコード:
%% ===================================================================
%% Author xiaotie
%% 2015-07-30
%% :LoopTimes
%% tc:t(Module, Function, ArgsList, LoopTimes).
%% :SpawnProcessesCount
%% tc:ct(Module, Function, ArgsList, SpawnProcessesCount).
%% ===================================================================
-module (tc).
-export ([t/4, ct/4]).
tc(M, F, A) ->
{Microsecond, _} = timer:tc (M, F, A),
Microsecond.
distribution(List, Aver) ->
distribution(List, Aver, 0, 0).
distribution([H|T], Aver, Greater, Less) ->
case H > Aver of
true ->
distribution(T, Aver, Greater + 1, Less);
false ->
distribution(T, Aver, Greater, Less + 1)
end;
distribution([], _Aver, Greater, Less) ->
{Greater, Less}.
%% ===================================================================
%% test: one process test N times
%% ===================================================================
t(M, F, A, N) ->
{Max, Min, Sum, Aver, Greater, Less} = loop ({M, F, A}, N),
io:format ("=====================~n"),
io:format ("execute [~p] times of {~p, ~p, ~p}:~n", [N, M, F, A]),
io:format ("Maximum: ~p(μs)\t~p(s)~n", [Max, Max / 1000000]),
io:format ("Minimum: ~p(μs)\t~p(s)~n", [Min, Min / 1000000]),
io:format ("Sum: ~p(μs)\t~p(s)~n", [Sum, Sum / 1000000]),
io:format ("Average: ~p(μs)\t~p(s)~n", [Aver, Aver / 1000000]),
io:format ("Greater: ~p~nLess: ~p~n", [Greater, Less]),
io:format ("=====================~n").
loop({M, F, A}, N) ->
loop ({M, F, A}, N, 1, 0, 0, 0, []).
loop({M, F, A}, N, I, Max, Min, Sum, List) when N >= I ->
Microsecond = tc (M, F, A),
NewSum = Sum + Microsecond,
if
Max == 0 ->
NewMax = NewMin = Microsecond;
Max < Microsecond ->
NewMax = Microsecond,
NewMin = Min;
Min > Microsecond ->
NewMax = Max,
NewMin = Microsecond;
true ->
NewMax = Max,
NewMin = Min
end,
loop ({M, F, A}, N, I + 1, NewMax, NewMin, NewSum, [Microsecond|List]);
loop({_M, _F, _A}, N, _I, Max, Min, Sum, List) ->
Aver = Sum / N,
{Greater, Less} = distribution(List, Aver),
{Max, Min, Sum, Aver, Greater, Less}.
%% ===================================================================
%% Concurrency test: N processes each test one time
%% ===================================================================
ct(M, F, A, N) ->
{Max, Min, Sum, Aver, Greater, Less} = cloop ({M, F, A}, N),
io:format ("=====================~n"),
io:format ("spawn [~p] processes of {~p, ~p, ~p}:~n", [N, M, F, A]),
io:format ("Maximum: ~p(μs)\t~p(s)~n", [Max, Max / 1000000]),
io:format ("Minimum: ~p(μs)\t~p(s)~n", [Min, Min / 1000000]),
io:format ("Sum: ~p(μs)\t~p(s)~n", [Sum, Sum / 1000000]),
io:format ("Average: ~p(μs)\t~p(s)~n", [Aver, Aver / 1000000]),
io:format ("Greater: ~p~nLess: ~p~n", [Greater, Less]),
io:format ("=====================~n").
cloop({M, F, A}, N) ->
CollectorPid = self(),
ok = loop_spawn({M, F, A}, CollectorPid, N),
collector(0, 0, 0, N, 1, []).
loop_spawn({M, F, A}, CollectorPid, N) when N > 0 ->
spawn_link(fun() -> worker({M, F, A}, CollectorPid) end),
loop_spawn({M, F, A}, CollectorPid, N - 1);
loop_spawn(_, _, 0) ->
ok.
collector(Max, Min, Sum, N, I, List) when N >= I ->
receive
{result, Microsecond} ->
NewSum = Sum + Microsecond,
if
Max == 0 ->
NewMax = NewMin = Microsecond;
Max < Microsecond ->
NewMax = Microsecond,
NewMin = Min;
Min > Microsecond ->
NewMax = Max,
NewMin = Microsecond;
true ->
NewMax = Max,
NewMin = Min
end,
collector(NewMax, NewMin, NewSum, N, I + 1, [Microsecond|List])
after
10000 ->
ok
end;
collector(Max, Min, Sum, N, _, List) ->
Aver = Sum / N,
{Greater, Less} = distribution(List, Aver),
{Max, Min, Sum, Aver, Greater, Less}.
worker({M, F, A}, CollectorPid) ->
Microsecond = tc(M, F, A),
CollectorPid ! {result, Microsecond}.
結果:10万同時プロセスでfindとfind 1にアクセスし、結果:
=====================
spawn [100000] processes of {tm, find, [<>]}:
Maximum: 1686(μs) 0.001686(s)
Minimum: 1(μs) 1.0e-6(s)
Sum: 237287(μs) 0.237287(s)
Average: 2.37287(μs) 2.3728699999999998e-6(s)
Greater: 28017
Less: 71983
=====================
ok
3> tm:ct1().
=====================
spawn [100000] processes of {tm, find1, [<>]}:
Maximum: 1862(μs) 0.001862(s)
Minimum: 4(μs) 4.0e-6(s)
Sum: 741330(μs) 0.74133(s)
Average: 7.4133(μs) 7.4133e-6(s)
Greater: 29711
Less: 70289
=====================
基本dirtyを何回か測定しましたreadは2マイクロ秒程度、dirty_index_readは7マイクロ秒程度です.性能は3倍程度.
まとめ:
テストの結果、mnesiaでデータをすばやく読み取りたい場合は、できるだけチェックしたフィールドをKeyとします.