• Save
Perl 非同期プログラミング
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

Perl 非同期プログラミング

on

  • 17,588 views

 

Statistics

Views

Total Views
17,588
Views on SlideShare
17,513
Embed Views
75

Actions

Likes
26
Downloads
0
Comments
1

7 Embeds 75

http://hokkaido.pm.org 52
https://twitter.com 7
http://www.slideshare.net 6
http://kurataka.com 5
http://twitter.com 2
http://b.hatena.ne.jp 2
http://paper.li 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
  • Perlでの非同期プログラミングについて、関連モジュールと汎用ラッパとしてのAnyEventの存在から、実際のプログラミングのツボまでをまとめている。++。
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • \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

Perl 非同期プログラミング Presentation 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. ご静聴ありがとう ございました