マルチタスクって奥が深い #mishimapm

7,155 views

Published on

2014/7/12に行われた Mishima.pm#1 で発表したトークのスライドです。

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
7,155
On SlideShare
0
From Embeds
0
Number of Embeds
743
Actions
Shares
0
Downloads
4
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

マルチタスクって奥が深い #mishimapm

  1. 1. マルチタスクって奥が深い OGATA Tetsuji (@xtetsuji) 2014/07/12 Mishima.pm#1
  2. 2. 自己紹介 • 尾形 鉄次 (OGATA Tetsuji) • Twitter: @xtetsuji • Blog: http://post.tetsuji.jp/
  3. 3. 今回は無事に静岡に来られた!
  4. 4. 2013/12/11 Mishima.pm#0 2013年12月に胃潰瘍で入院したときのツイートまとめ - Togetterまとめ http://togetter.com/li/607049
  5. 5. あれから半年 • 半年経過後の胃カメラ検査をつい先日してきました • 静岡前の胃カメラ、今度は死亡フラグじゃなかった • 珍しい位置の潰瘍だったけど、なんとか生きてます • あれから毎月激動で、公私ともに忙しいけれど、皆様の 温かいご支援で生きています
  6. 6. 今だから復習したい マルチタスク
  7. 7. 過去にもマルチタスクの話は 結構しているけど成長が(ry
  8. 8. 過去にしているトークの一例 • 「そのsleep、ちょっと待った」(PerlBeginners#13) • 「イベント駆動とノンブロッキング」(Hokkaido.pm#10) • 今回はこれらのプラスアルファな感じの話をします • ビギナー向けにちょうどよい感じ、という言い訳 • みんなで質疑応答をしたりといった感じでよろしくです
  9. 9. 色々なPerlのツール • forkや、Parallel::ForkManager、Parallel::Prefork など • 封印されしithreads (アッ、誰か来た) • AnyEvent前史のPOEフレームワーク • AnyEvent、そしてCoroといったMarc Lehmmanツール • 今昔IO非同期系ツール群
  10. 10. 結構雑にカジュアルに • マルチタスク=複数の仕事をこなす • 非同期=ノンブロッキング • 同期=ブロッキング • 情報系の学術論文でないのであれば、この辺りあんまり 厳密に区別しなくてもよいっぽい(頭の中でできることに 越した事はありません)
  11. 11. ithreadsが使われない理由 • Perlのスレッド(ithreads)は不安定だし効率が悪い • Perlはグローバルな状態だらけの世界観なので、後付け のスレッドもインタープリタプールを作ったり、色々大 変な事をしているので、同情してあげてください • Windowsにはforkがないので、WindowsのPerlでは Win32スレッドを使ったforkのエミューレーションをし ているそうです
  12. 12. forkモデル • fork=フォーク=分岐 • 途中で親と子に分かれてプログラムの分岐を行う • Perl組み込みのfork関数がそれを実現してくれる
  13. 13. forkサンプル #!/usr/bin/env perl! ! use strict;! use warnings;! use utf8;! ! binmode STDOUT, ':utf8';! binmode STDERR, ':utf8';! ! print "親です。プロセスIDは $$ です。開始します。n";! ! my $pid = fork; # ここで親と子で分岐! ! if ( $pid ) {! sleep 2;! print "親です。子のプロセスIDは $pid のようです。しばらく休みますn";! sleep 10;! print "親です。10秒待ちました。n";! } elsif ( $pid == 0 ) {! sleep 3;! print "子です。私のプロセスIDは $$ のようです。n";! for my $i (1..5) {! print "子です。${i}回目。n";! sleep 1;! }! print "子はしばらく待ちます。先に親が終了してプロンプトに戻りますn";! sleep 10;! } else {! die "forkできなかった?n";! }! ! print "pid=$pid $$=$$n"; # 親も子も通る
  14. 14. あんまりforkを直接書かない • 見てパッと理解できない • 多くの子プロセスを作るときにfork()を呼びまくった ら結構混乱する • 親と子でコミュニケーションするにはプロセス間通信が 一番プリミティブな方法かな • 多くのforkが必要になった場合には、これを抽象化した Parallel::ForkManagerが役に立つ
  15. 15. Parallel::ForkManagerの例 #!/usr/bin/env perl! ! use strict;! use warnings;! ! use LWP::UserAgent;! use Parallel::ForkManager;! ! my @urls = ( map { sprintf "http://example.jp/images/%02d.jpg" } (1..99) );! ! my $ua = LWP::UserAgent->new;! ! my $pm = Parallel::ForkManager->new(5); # 最大5プロセス並列! ! for my $url (@urls) {! my $pid = $pm->start and next;! # 子プロセスの処理! print "プロセスIDが $$ の子プロセスが $url からデータをダウンロードしますn";! ( my $filename = $url ) =~ s{.*/}{};! $ua->get($url, ":content_file" => $filename);! $pm->finish; # 子プロセスを終了! }
  16. 16. 並列ダウンロードと マルチタスク • 外界の影響を受けるダウンロードというタスクの場合、 同期的にダウンロードをするとサーバによって待たされ るケースがあったりする • RSSとかを大量にクロールするとか、死活問題 • 例えばParallel::ForkManagerで解決できる
  17. 17. ForkManagerとPrefork • Parallel::ForkManagerは並列クライアントを作るもの、 Parallel::Preforkは並列処理ができるforkモデルのサーバ を作るものと覚えておくとよい • Parallel::ForkManagerは相当以前からDebian/Ubuntu パッケージとしても提供されているので、システムPerl でも使いやすい • Parallel::Preforkは奥一穂さんによる和製モジュール
  18. 18. forkの問題点と言われること • プログラムのコピーなのでメモリを食う • Copy on Write(CoW)というOSの機構により倍々には ならないはずだけど、限界はある • プロセス間通信が面倒 • これは頑張るか、コストを気にしなければHTTP等の サーバを介したりするのがよいかも
  19. 19. とはいえforkはよく使う • UNIX/Linuxのサブプロセスの原点fork • 覚えておくと色々勉強になるし、自分もよく勉強してる • Perlのsystem関数はforkとexecの組み合わせ • 先輩プログラマが「フォーク」とか言っているときに、 ちょっと知った気になれるの重要
  20. 20. イベント駆動モデル • スレッドともforkとも若干違うマルチタスクモデル • Apacheのprefork MPMがAjax時代にまつわるC10K問題 に対抗できない代替として生まれたともいえるNginxの マルチタスクモデルとして注目された • Perlでは、AnyEventというイベント駆動フレームワーク が以前から主流で、以前からあった同種のイベント駆動 モジュールのインターフェースを統一したりもした
  21. 21. AnyEvent • 以前流行したPOEの後継にあたるものともいえる • Perlで動作する様々なイベント駆動フレームワークの、 今の事実上のデファクトスタンダード • 裏側のイベント処理実装に様々なものが選べる • 各種イベント(時間、I/O、シグナル、などなど)で処理を 走らせることができる
  22. 22. AnyEventの後ろの実装 • AnyEvent::Impl::* 以下にあるものが選べる • Cocoa、Event、FLTK、IOAsync、POE、Qt、EV、 EventLib、Glib、Irssi、Perl (AnyEvent標準の実装)、Tk • 通常はAnyEvent::Impl::Perlが選ばれるけど、EVを選ん だり、場所によって選択を変える場合がある • Marc Lehmann氏も「POEはやめとけ」と書いている
  23. 23. POEが衰退した理由 • 構造が複雑:OSとほぼ同じ、カーネル・ヒープ構造 • 書き方が複雑 • 静かにプログラムが異常終了していることが多かった • 重いとも言われていた
  24. 24. daemonを作るwhileループ • daemon的な常駐プログラムを作る場合、
 while(1){…} といった無限ループを作ることが定石 • とはいえ、無限ループにsleepをはさみ忘れたりすると、 CPU暴走してサーバが死んだりするので怖い • while無限ループはなるべく自前で書かない方がいいとい うのが私の持論
  25. 25. AnyEventの方法論 • AnyEvent::Impl::* によっても変わるけど、結局的に、 PerlやCのwhile(1){…}が一番根底で走っていると思っ て差し支えない • 特にAnyEvent::Impl::Perlの場合は、AnyEvent::Loopが それらしい
  26. 26. AnyEvent::Loopより sub run {! one_event while 1;! } one_event メソッドは多くの仕事をしていますが割愛
  27. 27. AnyEventの活用例 • クライアントでは各種IRCやTwitterボットなどで活用 • サーバではWebサーバ(Twiggyが有名)をはじめとした、 任意のTCPサーバが書ける • これらを組み合わせたりできるので、IRCクライアント でかつWebサーバというプログラムも書ける (Ikachanと いう良い実装例もある)
  28. 28. AnyEventで時間イベント #!/usr/bin/env perl! ! use strict;! use warnings;! use AnyEvent;! ! my $cv = AnyEvent->condvar; # 状態変数! my $timer1 = AnyEvent->timer(! after => 1,! cb => sub { print "timer1 hello!n"; },! interval => 2,! );! my $timer2 = AnyEvent->timer(! after => 1,! cb => sub { print "timer2 hello!n"; },! interval => 3,! );! my $timer3 = AnyEvent->timer(! after => 1,! cb => sub { print "timer3 hello!n"; },! interval => 5,! );! my $stop_timer = AnyEvent->timer(! after => 10,! cb => sub { $cv->send("end"); }, # 終わらせる! );! my $val = $cv->recv; # ループをまわす! print "terminate: $valn";
  29. 29. AnyEventで時間イベント • 最初はwhileループのほうが良いと思うけど、自分で気を つけてsleep書かなくてもいいし慣れるとこっちが良い • IRCボットとかだと、定時発言などもこれでできる • perldoc AnyEventをみたり、CPANでAnyEventで作られ たモジュールを見たりして少しずつ覚えていくといい
  30. 30. AnyEvent::Mac::Pasteboard • Macのクリップボード(ペーストボード)を監視して、変更 があったら指定の処理をするモジュールを書いてみた • これもタイマーで変更を定期監視しているだけ • Cocoaの知識があればもっと良い感じができるかも • その後AnyEvent::Clipboardも作りました(GitHub止まり)
  31. 31. その他 • CPANで「Async」というキーワードで検索してみる • AnyEventを入れるほどではないけど、非同期アクセスが 必要な場合に良い場合がある (HTTP::Asyncとか) • MojoliciousであればMojo::IOLoopとか • Mojolicious飲み会とかやりたいと思っているので、続き はそこで非同期飲み会やりましょう
  32. 32. 注意点とか • LWP::UserAgent等で長時間処理をブロックしたりする と、AnyEventの処理全体をブロックすることになるので ノンブロッキングなAnyEvent::HTTPなどを使おう • JavaScriptのAjaxやっている人だとコールバック的 • ドヤ顔で「AnyEventで(ry」とか言ってIO::Socket::INET 使っていたりすると、ブロッキングとか言われて恥ずか しい思いをします
  33. 33. 最後にいろいろ • ノンブロッキングのネットワークI/Oについては AnyEvent::Socketをベースに作ります • AnyEvent::SocketはSocketモジュールをベースに、ノン ブロッキングネットワークI/Oの方法論を元に書かれてい るようです • 基本的に、既に作られているL7層のモジュールを元に、 自分で新しいプログラムやモジュールを作ればしあわせ
  34. 34. 全然掘り起こせなかったですが 奥が深いので続きはどこかで
  35. 35. おしまい

×