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").