ProducerConsumer再び
30分プログラム、その432。前にやったProducerConsumerをもう一度やってみる。
前はJavaの実装を素直にErlangに移植しただけだった。でも、Channelがウェイトセットを持っているのがダサい。
じゃあ、なんでウェイトセットが必要かというと、ProducerやConsumerのスレッドを使い回すのが目的な気がする。Javaはスレッドの生成が重いから、それを避けたいんだと想像してる。
ということは、プロセス生成が軽いErlangじゃあウェイトセットはいらないんじゃないか、と思ったので作ってみた。ProducerがDataを作るたびに、Consumerを生成するようにしたら、ChannelにDataを貯める必要がなくなった。やったね。というか、これはThread-per-messageと呼ぶような気がちょっとする。
使い方
$ erl -noshell -s prodcons start -s init stop
...
B put Cake 102
A put Cake 103
C put Cake 104
Eat Cake 104
Eat Cake 103
Eat Cake 102
C put Cake 105
A put Cake 106
B put Cake 107
Eat Cake 107
Eat Cake 106
Eat Cake 105
B put Cake 108
A put Cake 109
C put Cake 110
C put Cake 111
A put Cake 112
B put Cake 113
B put Cake 114
A put Cake 115
C put Cake 116
Eat Cake 110
Eat Cake 109
Eat Cake 108
ソースコード
-module(prodcons). -compile([export_all]). some_work() -> timer:sleep(random:uniform(1000)). %%% number server number_server(No) -> receive {get,From} -> From ! No, number_server(No+1) end. number_server() -> Pid = spawn(fun () -> number_server(0) end), register(number,Pid). get_no() -> Self = self(), number ! {get,Self}, receive N -> N end. %%% eater eater(Cake)-> some_work(), io:format("Eat ~s~n",[Cake]). %%% cook cook(Table,Name) -> some_work(), Cake = io_lib:format("Cake ~p",[get_no()]), io:format("\t\t~s put ~s~n",[Name,Cake]), Table ! {put,Cake}, cook(Table,Name). %%% table table(Eater_fun)-> receive {put,Cake} -> spawn(fun ()-> Eater_fun(Cake) end), table(Eater_fun) end. %%% start start() -> number_server(), Table = spawn(fun () -> table(fun prodcons:eater/1) end), spawn(fun () -> cook(Table,"A") end), spawn(fun () -> cook(Table,"B") end), cook(Table,"C").