35
マルチタスクって奥が深い OGATA Tetsuji (@xtetsuji) 2014/ 07/12 Mishima.pm#1

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

Embed Size (px)

DESCRIPTION

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

Citation preview

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

マルチタスクって奥が深いOGATA Tetsuji (@xtetsuji)

2014/07/12 Mishima.pm#1

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

自己紹介

• 尾形 鉄次 (OGATA Tetsuji)

• Twitter: @xtetsuji

• Blog: http://post.tetsuji.jp/

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

今回は無事に静岡に来られた!

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

2013/12/11 Mishima.pm#0

2013年12月に胃潰瘍で入院したときのツイートまとめ - Togetterまとめ http://togetter.com/li/607049

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

あれから半年

• 半年経過後の胃カメラ検査をつい先日してきました

• 静岡前の胃カメラ、今度は死亡フラグじゃなかった

• 珍しい位置の潰瘍だったけど、なんとか生きてます

• あれから毎月激動で、公私ともに忙しいけれど、皆様の温かいご支援で生きています

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

今だから復習したい マルチタスク

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

過去にもマルチタスクの話は 結構しているけど成長が(ry

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

過去にしているトークの一例

• 「そのsleep、ちょっと待った」(PerlBeginners#13)

• 「イベント駆動とノンブロッキング」(Hokkaido.pm#10)

• 今回はこれらのプラスアルファな感じの話をします

• ビギナー向けにちょうどよい感じ、という言い訳

• みんなで質疑応答をしたりといった感じでよろしくです

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

色々なPerlのツール• forkや、Parallel::ForkManager、Parallel::Prefork など

• 封印されしithreads (アッ、誰か来た)

• AnyEvent前史のPOEフレームワーク

• AnyEvent、そしてCoroといったMarc Lehmmanツール

• 今昔IO非同期系ツール群

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

結構雑にカジュアルに

• マルチタスク=複数の仕事をこなす

• 非同期=ノンブロッキング

• 同期=ブロッキング

• 情報系の学術論文でないのであれば、この辺りあんまり厳密に区別しなくてもよいっぽい(頭の中でできることに越した事はありません)

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

ithreadsが使われない理由• Perlのスレッド(ithreads)は不安定だし効率が悪い

• Perlはグローバルな状態だらけの世界観なので、後付けのスレッドもインタープリタプールを作ったり、色々大変な事をしているので、同情してあげてください

• Windowsにはforkがないので、WindowsのPerlではWin32スレッドを使ったforkのエミューレーションをしているそうです

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

forkモデル

• fork=フォーク=分岐

• 途中で親と子に分かれてプログラムの分岐を行う

• Perl組み込みのfork関数がそれを実現してくれる

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

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"; # 親も子も通る

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

あんまりforkを直接書かない• 見てパッと理解できない

• 多くの子プロセスを作るときにfork()を呼びまくったら結構混乱する

• 親と子でコミュニケーションするにはプロセス間通信が一番プリミティブな方法かな

• 多くのforkが必要になった場合には、これを抽象化したParallel::ForkManagerが役に立つ

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

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; # 子プロセスを終了!}

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

並列ダウンロードと マルチタスク

• 外界の影響を受けるダウンロードというタスクの場合、同期的にダウンロードをするとサーバによって待たされるケースがあったりする

• RSSとかを大量にクロールするとか、死活問題

• 例えばParallel::ForkManagerで解決できる

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

ForkManagerとPrefork

• Parallel::ForkManagerは並列クライアントを作るもの、Parallel::Preforkは並列処理ができるforkモデルのサーバを作るものと覚えておくとよい

• Parallel::ForkManagerは相当以前からDebian/Ubuntuパッケージとしても提供されているので、システムPerlでも使いやすい

• Parallel::Preforkは奥一穂さんによる和製モジュール

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

forkの問題点と言われること

• プログラムのコピーなのでメモリを食う

• Copy on Write(CoW)というOSの機構により倍々にはならないはずだけど、限界はある

• プロセス間通信が面倒

• これは頑張るか、コストを気にしなければHTTP等のサーバを介したりするのがよいかも

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

とはいえforkはよく使う

• UNIX/Linuxのサブプロセスの原点fork

• 覚えておくと色々勉強になるし、自分もよく勉強してる

• Perlのsystem関数はforkとexecの組み合わせ

• 先輩プログラマが「フォーク」とか言っているときに、ちょっと知った気になれるの重要

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

イベント駆動モデル• スレッドともforkとも若干違うマルチタスクモデル

• Apacheのprefork MPMがAjax時代にまつわるC10K問題に対抗できない代替として生まれたともいえるNginxのマルチタスクモデルとして注目された

• Perlでは、AnyEventというイベント駆動フレームワークが以前から主流で、以前からあった同種のイベント駆動モジュールのインターフェースを統一したりもした

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

AnyEvent

• 以前流行したPOEの後継にあたるものともいえる

• Perlで動作する様々なイベント駆動フレームワークの、今の事実上のデファクトスタンダード

• 裏側のイベント処理実装に様々なものが選べる

• 各種イベント(時間、I/O、シグナル、などなど)で処理を走らせることができる

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

AnyEventの後ろの実装• AnyEvent::Impl::* 以下にあるものが選べる

• Cocoa、Event、FLTK、IOAsync、POE、Qt、EV、EventLib、Glib、Irssi、Perl (AnyEvent標準の実装)、Tk

• 通常はAnyEvent::Impl::Perlが選ばれるけど、EVを選んだり、場所によって選択を変える場合がある

• Marc Lehmann氏も「POEはやめとけ」と書いている

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

POEが衰退した理由

• 構造が複雑:OSとほぼ同じ、カーネル・ヒープ構造

• 書き方が複雑

• 静かにプログラムが異常終了していることが多かった

• 重いとも言われていた

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

daemonを作るwhileループ

• daemon的な常駐プログラムを作る場合、while(1){…} といった無限ループを作ることが定石

• とはいえ、無限ループにsleepをはさみ忘れたりすると、CPU暴走してサーバが死んだりするので怖い

• while無限ループはなるべく自前で書かない方がいいというのが私の持論

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

AnyEventの方法論

• AnyEvent::Impl::* によっても変わるけど、結局的に、PerlやCのwhile(1){…}が一番根底で走っていると思って差し支えない

• 特にAnyEvent::Impl::Perlの場合は、AnyEvent::Loopがそれらしい

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

AnyEvent::Loopより

sub run {! one_event while 1;!}

one_event メソッドは多くの仕事をしていますが割愛

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

AnyEventの活用例

• クライアントでは各種IRCやTwitterボットなどで活用

• サーバではWebサーバ(Twiggyが有名)をはじめとした、任意のTCPサーバが書ける

• これらを組み合わせたりできるので、IRCクライアントでかつWebサーバというプログラムも書ける (Ikachanという良い実装例もある)

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

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: $val\n";

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

AnyEventで時間イベント

• 最初はwhileループのほうが良いと思うけど、自分で気をつけてsleep書かなくてもいいし慣れるとこっちが良い

• IRCボットとかだと、定時発言などもこれでできる

• perldoc AnyEventをみたり、CPANでAnyEventで作られたモジュールを見たりして少しずつ覚えていくといい

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

AnyEvent::Mac::Pasteboard

• Macのクリップボード(ペーストボード)を監視して、変更があったら指定の処理をするモジュールを書いてみた

• これもタイマーで変更を定期監視しているだけ

• Cocoaの知識があればもっと良い感じができるかも

• その後AnyEvent::Clipboardも作りました(GitHub止まり)

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

その他• CPANで「Async」というキーワードで検索してみる

• AnyEventを入れるほどではないけど、非同期アクセスが必要な場合に良い場合がある (HTTP::Asyncとか)

• MojoliciousであればMojo::IOLoopとか

• Mojolicious飲み会とかやりたいと思っているので、続きはそこで非同期飲み会やりましょう

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

注意点とか• LWP::UserAgent等で長時間処理をブロックしたりすると、AnyEventの処理全体をブロックすることになるのでノンブロッキングなAnyEvent::HTTPなどを使おう

• JavaScriptのAjaxやっている人だとコールバック的

• ドヤ顔で「AnyEventで(ry」とか言ってIO::Socket::INET使っていたりすると、ブロッキングとか言われて恥ずかしい思いをします

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

最後にいろいろ• ノンブロッキングのネットワークI/Oについては

AnyEvent::Socketをベースに作ります

• AnyEvent::SocketはSocketモジュールをベースに、ノンブロッキングネットワークI/Oの方法論を元に書かれているようです

• 基本的に、既に作られているL7層のモジュールを元に、自分で新しいプログラムやモジュールを作ればしあわせ

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

全然掘り起こせなかったですが 奥が深いので続きはどこかで

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

おしまい