並列ダウンローダっぽい何か
30分プログラム、その672。サーバごとにスレッドを立ち上げて、並列でダウンロードするダウンローダを目指してみた。実際は、スレッドを立ち上げるとこまでしかやっていない。
Webからファイルをダウンロードするときは、なるべく並列化して効率をあげたい。でも、一個のサーバから同時に落しすぎると怒られちゃう。
というわけで、サーバごとにスレッドを立ち上げて、同じサーバからは一個しかダウンロードしてないけど、全体で見ると並列で落すダウンローダを目指してみた。
実際は、時間がなくてスレッドを管理する部分のコードしか書いてない。
使い方
example() -> % URLリスト。 % {<サーバ名>,<URL>}のようになっている。 Data = [{a,"http://example.com/"}, {a,"http://example.co.jp/"}, {b,"http://google.com"}], % ダウンロード開始 downloader:start(Data).
ソースコード
-module(downloader). -compile([export_all]). % ------------------------------ % download thread % ------------------------------ loop() -> receive {url,Url} -> io:format("Now downloading: ~p~n",[Url]), timer:sleep(1000), loop(); {close,From} -> From ! bye end. download() -> spawn(fun loop/0). % ------------------------------ % manage thread % ------------------------------ get_pid(Table,Key)-> case ets:lookup(Table,Key) of [] -> Pid = download(), ets:insert(Table,{Key,Pid}), Pid; [{Key,Pid}] -> Pid end. start(_,[]) -> ok; start(Table,[{Key,Url}|Xs]) -> get_pid(Table,Key) ! {url,Url}, start(Table,Xs). waits_for(0) -> bye; waits_for(N) -> receive bye -> waits_for(N-1) end. waits(Pids) -> lists:foreach(fun(Pid) -> Pid ! {close,self()} end, Pids), waits_for(length(Pids)). start(Xs)-> Table = ets:new(table,[set]), start(Table,Xs), Pids = lists:map(fun({_Key,Pid})->Pid end, ets:tab2list(Table)), waits(Pids), ets:delete(Table). % ------------------------------ % example % ------------------------------ example() -> Data = [{a,"http://example.com/"}, {a,"http://example.co.jp/"}, {b,"http://google.com"}], start(Data).