Last active
August 29, 2015 14:11
-
-
Save sile/5433cfbd51bf8d7d5cdc to your computer and use it in GitHub Desktop.
Erlangで書かれた自作ライブラリ群の紹介 ref: http://qiita.com/sile/items/05e8e1c3bd84dfc01448
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%%% | |
%%% 基本的な使い方 | |
%%% | |
%% ハッシュリングの作成 | |
> Nodes = lists:map(fun hash_ring_node:make/1, [a,b,c,d,e]). | |
[{hash_ring_node,a,a,1}, | |
{hash_ring_node,b,b,1}, | |
{hash_ring_node,c,c,1}, | |
{hash_ring_node,d,d,1}, | |
{hash_ring_node,e,e,1}] | |
> Ring0 = hash_ring:make(Nodes). | |
%% キーを担当するノードを検索する | |
> hash_ring:find_node(key_1, Ring0). | |
{ok,{hash_ring_node,c,c,1}} | |
%% ノードの削除 (and 再検索) | |
> hash_ring:find_node(key_1, hash_ring:remove_nodes([c], Ring0)). | |
{ok,{hash_ring_node,b,b,1}} | |
%%% | |
%%% 処理性能目安 | |
%%% | |
%% 構築: ノード数=100 | |
> {Time1, Ring1} = timer:tc(fun() -> hash_ring:make(lists:map(fun hash_ring_node:make/1, lists:seq(1, 100))) end). | |
> Time1 / 1000000. % 秒単位に変換 | |
0.144733 % 0.144秒 | |
%% 検索: 検索回数=10万回 | |
> Keys = lists:seq(1, 100000). | |
> {Time2, _} = timer:tc(fun () -> lists:foreach(fun (Key) -> hash_ring:find_node(Key, Ring1) end, Keys) end). | |
> Time2 / 1000000. | |
0.399199 % 0.399秒 (25万/秒) | |
%%% | |
%%% バラつき度目安 | |
%%% | |
> lists:sort( | |
dict:to_list( | |
lists:foldl(fun (K, Acc) -> dict:update_counter(K, 1, Acc) end, | |
dict:new(), | |
[begin {ok, N} = hash_ring:find_node(Key, Ring1), hash_ring_node:get_key(N) end || Key <- Keys]))). | |
[{1,1068}, % おおよそ均等? | |
{2,923}, | |
{3,942}, | |
{4,1006}, | |
{5,1084}, | |
{6,928}, | |
{7,969}, | |
{8,1031}, | |
{9,954}, | |
{10,995}, | |
{11,962}, | |
{12,1009}, | |
{13,974}, | |
{14,975}, | |
{15,1032}, | |
{16,997}, | |
{17,1030}, | |
{18,1012}, | |
{19,994}, | |
{20,953}, | |
{21,1038}, | |
{22,955}, | |
{23,1033}, | |
{24,959}, | |
{25,950}, | |
{26,1019}, | |
{27,980}, | |
{28,...}, | |
{...}|...] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%% 構築 | |
> Trie0 = hashtrie:new(). | |
{hashtrie,0,64,0, | |
{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}} | |
%% 要素追加 | |
> Trie1 = hashtrie:store(key, value, Trie0). | |
{hashtrie,1,64,0, | |
{[],[],[],[],[],[],[],[],[], | |
[{key,value}], | |
[],[],[],[],[],[]}}. | |
%% 要素検索 | |
> hashtrie:find(key, Trie1). | |
{ok,value} | |
> hashtrie:find(hogge, Trie1). | |
error |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%% デコード | |
> jsone:decode(<<"[1,2,3]">>). | |
[1,2,3] | |
%% エンコード | |
> jsone:encode([1,2,3]). | |
<<"[1,2,3]">> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ make start | |
%% 名前管理サーバプロセスを起動 | |
> local:start_name_server(sample_ns). | |
ok | |
> local:which_name_servers(). | |
[sample_ns]. | |
%% 名前登録 | |
> self(). | |
<0.33.0> | |
> local:register_name({sample_ns, hoge}, self()). % 名前は {名前管理サーバ名, プロセス名} の形式で指定する | |
yes | |
> local:register_name({sample_ns, [a,b,c]}, spawn(timer, sleep, [infinity])). % アトム以外のプロセス名も可 | |
yes | |
%% 検索 | |
> local:whereis_name({sample_ns, hoge}). | |
<0.33.0> | |
> local:whereis_name({sample_ns, fuga}). | |
undefined % 未登録 | |
%% 登録済みプロセス一覧を取得 | |
> local:which_processes(sample_ns). | |
[{[a,b,c],<0.42.0},{hoge, <0.33.0>}]. | |
> local:which_processes(sample_ns, ['_','_','_']). % パターン(ets:match_pattern/0)で絞り込むことも可 | |
[{[a,b,c],<0.42.0>}] | |
%% 登録解除 | |
> local:unregister_name({sample_ns, hoge}). | |
ok | |
> local:whereis_name({sample_ns, hoge}). | |
undefined | |
%% local:name_server_child_spec/1は、監視ツリーに名前管理プロセスを登録する際の推奨ChildSpecを返す | |
> local:name_server_child_spec(sample_ns). | |
{sample_ns,{local_name_server,start_link,[sample_ns]}, | |
permanent,5000,worker, | |
[local_name_server]} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
erl -pa ebin /path/to/logi_tty/ebin | |
> applicatoin:ensure_all_started(logi_tty). | |
{ok, [logi, logi_tty]} | |
> logi:info("hello"). % まだ何も表示されない | |
logi_default_logger | |
> logi_tty:install(info). % infoレベル以上のログは、端末に出力されるようにバックエンドを登録 | |
ok | |
> logi:info("hello"). % 表示される | |
2014-12-14 03:24:24.310 [info] nonode@nohost <0.33.0> undefined:0 [] hello | |
logi_default_logger | |
> logi:debug("hello"). % infoレベル以下は表示されない | |
logi_default_logger | |
%% ヘッダ設定 | |
> logi:set_headers([{key1, val1},{key2,val2}]). | |
> logi:info("hello"). | |
2014-12-14 03:25:24.410 [info] nonode@nohost <0.33.0> undefined:0 [key1=val1,key2=val2] hello | |
logi_defaul_logger | |
%%% ログ出力先の変更 | |
> logi:start_logger(hoge_logger). % 別のロガーを起動 (logi_default_loggerは最初に自動で起動している) | |
ok | |
> logi:which_loggers(). | |
[hoge_logger,logi_default_logger] | |
> logi:info(hoge_logger, "hello", []). % 出力先ロガーを指定して実行: まだ何も表示されない | |
hoge_logger | |
> logi_tty:install(hoge_logger, debug). % debugレベルでバックエンドを登録 | |
ok | |
> logi:debug(hoge_logger, "hello", []). % こっちはdebugレベルでも出力される | |
2014-12-14 03:29:16.868 [debug] nonode@nohost <0.54.0> undefined:0 [] hello | |
hoge_logger |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ ./rebar shell | |
%% 実プロセスの起動時刻を指定する | |
> After = fun (Seconds) -> {Mega, Sec, Micro} = now(), {Mega, Sec + Seconds, Micro} end. | |
> proxy:spawn(erlang, apply, | |
[fun (Start) -> io:format("~p hello: ~p sec\n", [self(), timer:now_diff(now(), Start) / 1000000]) end, | |
[now()]], % 呼び出し時刻を渡す | |
[{proxy_lifetime, [{start_time, After(5)}]}]). % 五秒後に起動するように指定 | |
<0.119.0> % 呼び出し元に返されるのはプロキシプロセスのPID | |
<0.121.0> hello: 5.001993 sec % 実プロセスは五秒後に起動 | |
%% 再起動回数を指定する | |
> proxy:spawn(io, format, ["hello\n"], | |
[{proxy_restart, [{max_restart, 3}]}]). % 三回までは再起動する | |
<0.122.0> | |
hello | |
hello | |
hello | |
%% プロキシプロセスは、受け取ったメッセージを実プロセスに転送する | |
> Pid = proxy:spawn(fun () -> receive Msg -> io:format("~p received: ~p\n", [self(), Msg]) end end, []). | |
> Pid ! hello. | |
<0.131.0> received: hello | |
hello |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ ./rebar shell | |
%%% | |
%%% erlang:open_port/2の場合の挙動 | |
%%% | |
%% 適当に長い時間を指定して、sleepコマンドを起動 | |
> Port0 = erlang:open_port({spawn_executable, "/bin/sleep"}, [{args, ["1000"]}]). | |
#Port<0.5076> | |
> erlang:port_info(Port0). | |
[{name,"/bin/sleep"}, | |
{links,[<0.39.0>]}, | |
{id,40608}, | |
{connected,<0.39.0>}, | |
{input,0}, | |
{output,0}, | |
{os_pid,11118}] % プロセスIDは'11118' | |
> io:format(os:cmd("ps | grep sleep")). | |
11118 ? 00:00:00 sleep % sleepは起動している | |
ok | |
%% ポート停止 | |
> erlang:port_close(Port0). | |
true | |
> erlang:port_info(Port0). | |
undefined % ポートは閉じている | |
> io:format(os:cmd("ps | grep sleep")). | |
11118 ? 00:00:00 sleep % sleepは生存している | |
ok | |
%% 呼び出し元プロセス停止 | |
> exit(kill). | |
** exception exit: kill | |
> io:format(os:cmd("ps | grep sleep")). | |
11118 ? 00:00:00 sleep % まだsleepは生存している | |
ok | |
%% 仕方がないのでkillコマンドで停止 | |
> os:cmd("kill 11118"). | |
> io:format(os:cmd("ps | grep sleep")). | |
ok | |
%%% | |
%%% safeexec:open_port/2の場合の挙動 | |
%%% | |
> Port1 = safeexec:open_port({spawn_executable, "/bin/sleep"}, [{args, ["1000"]}]). % 指定する引数は同様 | |
#Port<0.5769> | |
> erlang:port_info(Port1). | |
[{name,"/path/to/safeexec/priv/safeexec"}, % Erlangが直接起動するのはsafeexecコマンド | |
{links,[<0.76.0>]}, | |
{id,46152}, | |
{connected,<0.76.0>}, | |
{input,0}, | |
{output,0}, | |
{os_pid,11282}] % プロセスIDは'11282' | |
> io:format(os:cmd("ps | grep -E 'safeexec|sleep'")). | |
11282 ? 00:00:00 safeexec | |
11283 ? 00:00:00 sleep % sleepは、safeexecの子プロセスとして起動 | |
ok | |
%% ポート停止 | |
> erlang:port_close(Port1). | |
true | |
> io:format(os:cmd("ps | grep -E 'safeexec|sleep'")). % 外部コマンドも終了 | |
ok | |
%% 呼び出し元プロセスが終了した場合 | |
> safeexec:open_port({spawn_executable, "/bin/sleep"}, [{args, ["1000"]}]). | |
> io:format(os:cmd("ps | grep -E 'safeexec|sleep'")). | |
11339 ? 00:00:00 safeexec | |
11340 ? 00:00:00 sleep | |
ok | |
> exit(kill). | |
** exception exit: kill | |
> io:format(os:cmd("ps | grep -E 'safeexec|sleep'")). % 外部コマンドも終了 | |
ok |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ ./rebar shell | |
%%% | |
%%% 基本的な使い方 (インタフェース的にはdictに近い) | |
%%% | |
%% 構築 | |
> Tree0 = splay_tree:new(). | |
nil | |
%% 要素追加 | |
> Tree1 = splay_tree:store(key1, value1, Tree0). | |
{key1,value1} | |
> Tree2 = splay_tree:store(key2, value2, Tree1). | |
{key2,value2,{key1,value1},nil} | |
%% 要素検索 | |
> {_, Tree3} = splay_tree:find(key1, Tree2). | |
{{ok,value1},{key1,value1,nil,{key2,value2}}} % スプレー木は検索時にも木の部分的なリバランシングが行われる | |
> Tree2 =/= Tree3. | |
tree | |
> splay_tree:lookup(key1, Tree3). % lookup/2を使うことで検索結果だけを取得することも可能だが、基本的には非推奨 | |
{ok, value1} | |
%%% | |
%%% 優先順位付きキューとして使用する例 | |
%%% | |
> Queue0 = splay_tree:from_list([{N, N} || N <- lists:seq(1, 10)]). | |
{10,10, | |
{9,9, | |
{8,8, | |
{7,7, | |
{6,6,{5,5,{4,4,{3,3,{2,2,{1,1},nil},nil},nil},nil},nil}, | |
nil}, | |
nil}, | |
nil}, | |
nil} | |
%% take_smallest/1で先頭要素(= 優先順序が高い要素)を取り出せる | |
> {Front, Queue1} = splay_tree:take_smallest(Queue0), Front. | |
{ok,1,1} | |
%% split/2を使うことで任意の地点で分割可能 | |
> {Queue2, Queue3} = splay_tree:split(4, Queue1). | |
> splay_tree:to_list(Queue2). | |
[{2,2},{3,3}] | |
> splay_tree:to_list(Queue3). | |
[{4,4},{5,5},{6,6},{7,7},{8,8},{9,9},{10,10}] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment