Your SlideShare is downloading. ×
Perl 非同期プログラミング
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Perl 非同期プログラミング

16,538

Published on

Published in: Technology
1 Comment
27 Likes
Statistics
Notes
  • Perlでの非同期プログラミングについて、関連モジュールと汎用ラッパとしてのAnyEventの存在から、実際のプログラミングのツボまでをまとめている。++。
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
16,538
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
0
Comments
1
Likes
27
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Transcript

    • 1. 非同期プログラミング with Perl 2010/08/07 Japan Perl Association 代表理事 株式会社ライブドア 牧 大 輔 (@lestrrat)
    • 2. さっそくですが 「複数URLに接続してHTTP GETするコード」
    • 3. 普通の書き方use strict;use LWP::UserAgent;my @urls = qw( http://www.livedoor.com/ http://www.dena.jp/ http://mixi.jp/ http://www.gaiax.co.jp/);my $ua = LWP::UserAgent->new();foreach my $url (@urls) {   my $res = $ua->get( $url );   ...}
    • 4. ポイント•シンプル!•命令を順番に処理•ソケットからの読み込みに時間がかかると次の処理に進めない
    • 5. 理想•とりあえず可能な限りのホストに接続•接続できたらとりあえずHTTPリクエスト発行•読み込み可能なところ(先に返信が来たところから)読み込む
    • 6. read•read(2) は読み込めるデータが到着するまでブロックする•一個だけ遅いホストがあると全体が遅くなる :/
    • 7. 効率よくread
    • 8. 効率よくread ソケット1
    • 9. 効率よくread ソケット1 ソケット2
    • 10. 効率よくread ソケット1 ソケット2 ソケット3
    • 11. 効率よくread 読める? ソケット1 (データ来た?) ソケット2 ソケット3
    • 12. 効率よくread ソケット1 読める? ソケット2 (データ来た?) ソケット3
    • 13. 効率よくread ソケット1 ソケット2 読める? ソケット3 (データ来た?)
    • 14. 効率よくread ソケット1 ソケット2 読める? 来た! ソケット3 (データ来た?) 読み込め!
    • 15. 効率よくread ソケット1 ソケット2 読める? (データ来た?)
    • 16. 効率よくread 読める? ソケット1 (データ来た?) ソケット2
    • 17. 効率よくread 読める? 来た! ソケット1 (データ来た?) 読み込め! ソケット2
    • 18. 効率よくread 読める? (データ来た?) ソケット2
    • 19. 効率よくread 読める? ソケット2 (データ来た?)
    • 20. 効率よくread 来た! 読める? ソケット2 読み込め! (データ来た?)
    • 21. 効率よくread 読める? (データ来た?)
    • 22. 効率よくread
    • 23. イベント駆動
    • 24. メインループ(プログラムの進行) を他人に任せる
    • 25. イベントループ = while ( $still_alive ) { ... 処理 ... }
    • 26. ループから呼ばれるコールバックを登録する
    • 27. イベントループ キュー コールバック 実行! コールバック コールバック コールバック このイベントを待っているイベント発生! コールバックがあるか確認
    • 28. イベント?非同期?• イベント駆動の仕組みの中でI/O処理→ファイルハンドル等を「非同期モード」にする• イベント駆動のメリットを生かすにはI/O等ブロックする処理が多いときに使う•よって「非同期プログラミング」と「イベント駆動プログラミング」は同義で使うことが多い
    • 29. AnyEvent
    • 30. なんで?
    • 31. POEDanga::SocketIO::AsyncEventGlib Qt
    • 32. お互いに互換性無し
    • 33. AnyEvent非同期フレームワークのラッパ
    • 34. 汎用API これだけ覚えていればOK AnyEventデフォルト Event その他 Glib POE EV
    • 35. standard API++
    • 36. 混ぜることもできる 例:POE+EV
    • 37. 新規に書くならAnyEventでおk
    • 38. 先にお知らせ
    • 39. 名前空間
    • 40. AnyEvent vs AE
    • 41. スタイルの違いだけAnyEvent->timer(    after => $after,    interval => $interval,    cb => sub {        ....    });AE::timer $after, $interval, sub {    ...};
    • 42. ここではAEを 使います
    • 43. 基本コンポーネント•ループ•ウォッチャー•コンディション変数•ガード
    • 44. ウォッチャー
    • 45. AnyEventコンポーネント IO コールバック 実行! タイマー コールバック 「ウォッチャー」
    • 46. AnyEventを使う = ウォッチャーの管理をする
    • 47. Timermy $timer;$timer = AE::timer 0, 1, sub {    warn “timer invoked”;    undef $timer;};
    • 48. I/Omy $io;$io = AE::io $fh, $read_or_write, sub {    .... # $fhから読んだり、$fhに書いたり    undef $io;}; 注意:$fhは非同期モードに指定しておく
    • 49. fh_nonblockinguse AnyEvent::Util qw(fh_nonblocking);my $fh = get_socket(...);fh_nonblocking $fh, 1;my $io;$io = AE::io $fh, 0, sub { ... };
    • 50. シグナルmy $sig;$sig = AE::signal "TERM", sub { ...    undef $sig;};
    • 51. 子プロセスmy $child;$child = AE::child $pid, sub {    ...    undef $child;};
    • 52. 待機状態my $idle;$idle = AE::idle sub {    ...    undef $idle;};
    • 53. なにこれ?my $timer;$timer = AE::timer 0, 1, sub {    warn “timer invoked”;    undef $timer;};
    • 54. Perl:スコープが終わるとメモリが解放される
    • 55. AnyEvent:ウォッチャーが解放されるとイベントがキャンセルされる
    • 56. NG{    my $timer = AE::timer 0, 1, sub {        warn “timer invoked”; # 走らない!    };} # ここにたどり着いた時点で $timerが解放 スコープ終了。リソース解放され $timerも解放されてしまう
    • 57. Goodmy $timer;$timer = AE::timer 0, 1, sub {    ... # どこかで $timer を使うコード    undef $timer; # 明示的に解放しないと消えない} クロージャで使用されているため 明示的に解放されるまで生き残る
    • 58. コンディション変数• いくつかの違う機能が同居してる• ちょっと混乱しやすい• が、重要• 以降 「condvar」と表記
    • 59. 1. 何かを待つ•現処理の流れを「止める」•「知らせ」を待つ•スクリプトレベルでは「ループに制御を渡す」
    • 60. #!perluse strict;use AnyEvent;my $cv = AE::cv {   print "Endn";};my $timer;$timer = AE::timer 10, 0, sub {   print "Waited 10 seconds!n";   undef $timer;   $cv->send;};$cv->recv;
    • 61. #!perluse strict;use AnyEvent;my $cv = AE::cv {   print "Endn";};my $timer;$timer = AE::timer 10, 0, sub {   print "Waited 10 seconds!n";   undef $timer;   $cv->send;};$cv->recv; 知らせ が来るまでこの次にはいかない (→イベントループが起動)
    • 62. #!perluse strict;use AnyEvent;my $cv = AE::cv {   print "Endn";};my $timer;$timer = AE::timer 10, 0, sub {   print "Waited 10 seconds!n";   undef $timer;   $cv->send; タイマーが起動したら 知らせ を送る};$cv->recv;
    • 63. #!perluse strict;use AnyEvent;my $cv = AE::cv {   print "Endn";};my $timer;$timer = AE::timer 10, 0, sub {   print "Waited 10 seconds!n";   undef $timer;   $cv->send;};$cv->recv; 知らせ が来たら次の処理へ (→スクリプト終了)
    • 64. #!perluse strict;use AnyEvent;my $cv = AE::cv {   print "Endn";};my $timer;$timer = AE::timer 10, 0, sub {   print "Waited 10 seconds!n";   undef $timer;   $cv->send;};$cv->recv;
    • 65. #!perluse strict;use AnyEvent;my $timer;$timer = AE::timer 10, 0, sub {   print "Waited 10 seconds!n";   undef $timer;};
    • 66. #!perluse strict;use AnyEvent;my $timer;$timer = AE::timer 10, 0, sub {   print "Waited 10 seconds!n";   undef $timer;}; 何も「待つ」ことがなかったので イベントループも起動しない
    • 67. #!perluse strict;use AnyEvent;my $timer;$timer = AE::timer 10, 0, sub {   print "Waited 10 seconds!n";   undef $timer;};
    • 68. 2. 複数の知らせを待つ•フラグをあげる→落とす•一つでもフラグがあがっていれば待つ•フラグが全部落ちるとお知らせ
    • 69. #!perluse strict;use AnyEvent;my @delay = (1, 2, 5, 10);my $cv = AE::cv { print "All timers are donen" };foreach my $delay (@delay) {   my $timer;   $cv->begin;   $timer = AE::timer $delay, 0, sub {      print "Timer for delay = $delayn";      undef $timer;      $cv->end;   };}$cv->recv;
    • 70. #!perluse strict;use AnyEvent;my @delay = (1, 2, 5, 10);my $cv = AE::cv { print "All timers are donen" };foreach my $delay (@delay) {   my $timer;   $cv->begin; フラグをあげる   $timer = AE::timer $delay, 0, sub {      print "Timer for delay = $delayn";      undef $timer;      $cv->end;   };}$cv->recv;
    • 71. #!perluse strict;use AnyEvent;my @delay = (1, 2, 5, 10);my $cv = AE::cv { print "All timers are donen" };foreach my $delay (@delay) {   my $timer;   $cv->begin;   $timer = AE::timer $delay, 0, sub {      print "Timer for delay = $delayn";      undef $timer;      $cv->end; フラグを落とす   };}$cv->recv;
    • 72. #!perluse strict;use AnyEvent;my @delay = (1, 2, 5, 10);my $cv = AE::cv { print "All timers are donen" };foreach my $delay (@delay) {   my $timer;   $cv->begin;   $timer = AE::timer $delay, 0, sub {      print "Timer for delay = $delayn";      undef $timer;      $cv->end;   };}$cv->recv; フラグが全部落ちたらお知らせ
    • 73. #!perluse strict;use AnyEvent;my @delay = (1, 2, 5, 10);my $cv = AE::cv { print "All timers are donen" };foreach my $delay (@delay) {   my $timer;   $cv->begin;   $timer = AE::timer $delay, 0, sub {      print "Timer for delay = $delayn";      undef $timer;      $cv->end;   };}$cv->recv;
    • 74. 3. 処理終了時の コールバック•何か戻り値が必要な時処理結果を待つ•ウォッチャーを作る関数に知らせて欲しいcondvarを渡す
    • 75. #!perluse strict;use AnyEvent;sub add {   my ($x, $y, $cv) = @_;   my $timer;   $timer = AE::timer 5, 0, sub {       $cv->send( $x + $y );       undef $timer;   };}my $cv = AE::cv {   my $cv = shift;   my ($result) = $cv->recv;   print "Result = $resultn";};add( 3, 2, $cv );$cv->recv;
    • 76. #!perluse strict;use AnyEvent;sub add {   my ($x, $y, $cv) = @_;   my $timer;   $timer = AE::timer 5, 0, sub {       $cv->send( $x + $y );       undef $timer;   };}my $cv = AE::cv {   my $cv = shift;   my ($result) = $cv->recv;   print "Result = $resultn";};add( 3, 2, $cv ); 結果を受け取るコールバックを渡す$cv->recv;
    • 77. #!perluse strict;use AnyEvent;sub add {   my ($x, $y, $cv) = @_;   my $timer;   $timer = AE::timer 5, 0, sub {       $cv->send( $x + $y ); 計算結果をcondvarに渡す       undef $timer;   };}my $cv = AE::cv {   my $cv = shift;   my ($result) = $cv->recv;   print "Result = $resultn";};add( 3, 2, $cv );$cv->recv;
    • 78. #!perluse strict;use AnyEvent;sub add {   my ($x, $y, $cv) = @_;   my $timer;   $timer = AE::timer 5, 0, sub {       $cv->send( $x + $y );       undef $timer;   };}my $cv = AE::cv {   my $cv = shift;   my ($result) = $cv->recv; 結果を受け取る   print "Result = $resultn";};add( 3, 2, $cv );$cv->recv;
    • 79. #!perluse strict;use AnyEvent;sub add {   my ($x, $y, $cv) = @_;   my $timer;   $timer = AE::timer 5, 0, sub {       $cv->send( $x + $y );       undef $timer;   };}my $cv = AE::cv {   my $cv = shift;   my ($result) = $cv->recv;   print "Result = $resultn";};add( 3, 2, $cv );$cv->recv;
    • 80. 基本はこれだけ•ウォッチャーとcondvarだけで基本的に全てまかなえる•実際にはこれらを使った高レベルライブラリを使う
    • 81. AnyEventで 「複数URLに接続してHTTP GETするコード」
    • 82. AnyEvent::HTTP
    • 83. use strict;use AnyEvent;use AnyEvent::HTTP;my @urls = qw( http://www.livedoor.com/ http://www.dena.jp/ http://mixi.jp/ http://www.gaiax.co.jp/);my $cv = AE::cv {   print "Fetched all urls!n";};my $guard;foreach my $url (@urls) {   $cv->begin;   $guard = http_get $url, sub {      print "Got $urln";      undef $guard;      $cv->end;   }}$cv->recv;
    • 84. 以上!•万が一どれかが遅くても、他のURLは先に処理される
    • 85. ライブラリ AnyEvent::Twitter AnyEvent::Memcached AnyEvent::FriendFeed::RealtimeAnyEvent::Twitter::Stream AnyEvent::ReverseHTTP AnyEvent::HTTP::MXHR AnyEvent::CouchDB AnyEvent::SuperFeedr AnyEvent::AIO AnyEvent::BDB AnyEvent::DNS AnyEvent::Beanstalk AnyEvent::DBI AnyEvent::SNMP AnyEvent::MPAnyEvent::Gearman AnyEvent::XMPP Cache::Memcached::AnyEvent
    • 86. TwiggyPlack用非同期HTTPサーバー
    • 87. 1 スレッド!複数接続高速処理
    • 88. plackup -s Twiggy ...
    • 89. ちょっとずつレスポンスuse strict;use AnyEvent;sub {   my $env = shift;   return sub {      my $start_response = shift;      my $writer = $start_response->( [         200,         [ "Content-Type" => "text/plain" ]      ]);      my $count = 1;      my $t; $t = AE::timer 2, 2, sub {         $writer->write( ($count * 2) . "秒たったよ!n");         if ($count++ == 5) {            undef $t;            $writer->close;         }      };   }}
    • 90. 用途 非同期サーバー•接続後切断しない or •何らかのイベント待っている•いつ来るかわからないデー •メッセージキュー、速いか遅タを待っている いかわからないサービス等
    • 91. プロキシ•外部サーバーと連携するサービス •サーバーの性能を自分でコントロールできな い場合など•某SNSとか某SNSとか
    • 92. イベントサーバー•ブラウザゲーム•複数のクライアントが同時にイベントを共有する場合など
    • 93. 注意•「やりたいから」非同期にすると失敗する•「必要があるから」使うべき•非同期コードは難しくなる
    • 94. 非同期にする条件• リアルタイム性が重要 • いつ起こるか分からない •ポーリングではリクエスト回数が多すぎる• I/O待ちが多い •データを常時送り続けているのは x •待ち時間が長いとメリットがある
    • 95. 非同期にしない理由•コードが複雑になる•コードが複雑になる•コードが複雑になる•コードが複雑になる•コードが複雑になる
    • 96. 必要な時だけ使う =効果絶大
    • 97. Questions?
    • 98. ご静聴ありがとう ございました

    ×