Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
がんばれPHP FIBER がんばれPHP FIBER いがらし いがらし
Slide 2
Slide 2 text
話すこと 話すこと Fiberの紹介
Slide 3
Slide 3 text
私は誰ですか 私は誰ですか プログラマー 34才 ⽣まれも育ちも仙台 好きな⾔語はC
Slide 4
Slide 4 text
FIBERとは FIBERとは 協調マルチタスクのユーザスレッド コルーチン/グリーンスレッドとも呼ばれる Fiberという名前はWin32APIとかRubyとかで使わ れている
Slide 5
Slide 5 text
PHP FIBER PHP FIBER 去年から上海のlvhtさんが作ってる拡張 PHPのコアにFiberを⼊れようとしてる https://github.com/fiberphp/fiber-ext
Slide 6
Slide 6 text
PHP RFC: Fiber https://wiki.php.net/rfc/fiber
Slide 7
Slide 7 text
何ができる︖ 何ができる︖
Slide 8
Slide 8 text
単純な例 単純な例 function func() { return Fiber::yield(1); } $fiber = new Fiber(function ($a) { $b = Fiber::yield($a); $c = func(); return $c.$b; }); echo $fiber->resume(2); // echo 2 echo $fiber->resume("world"); // echo 1 echo $fiber->resume("hello "); // echo "hello world"
Slide 9
Slide 9 text
function func() { return/* 11 */ Fiber::yield(1)/* 8 */; } $fiber =/* 1 */ new Fiber(function ($a) { $b =/* 6 */ Fiber::yield($a)/* 3 */; $c =/* 12 */ func()/* 7 */; return $c.$b;/* 13 */ }); echo/* 4 */ $fiber->resume(1)/* 2 */; // echo 3 echo/* 9 */ $fiber->resume("world")/* 5 */; // echo 1 echo/* 14 */ $fiber->resume("hello ")/* 10 */; // echo "hello
Slide 10
Slide 10 text
Fiber = 中断/再開できる関数 Generatorのyieldと違いネストした呼び出しから 抜けられる 何が嬉しいか︖ 使い道は⾊々、I/O多重化とか
Slide 11
Slide 11 text
I/O多重化(てきとー) I/O多重化(てきとー) // query()やfetchAll()が内部でノンブロッキングI/OとFiber::yield()を $scheduler = new Scheduler(); $scheduler->add(new Fiber(function() { $db = ConnectionPool::getConnection(); var_dump($db->query('なんかSQL1')->fetchAll()); })); $scheduler->add(new Fiber(function() { $db = ConnectionPool::getConnection(); var_dump($db->query('なんかSQL2')->fetchAll()); })); while ($scheduler->run()) {} // 中でFiberをresume
Slide 12
Slide 12 text
No content
Slide 13
Slide 13 text
DBALでノンブロッキングI/OとFiber::yield()を利⽤ DBALからFiber::yield()で抜ける先となり、次の処 理を選ぶ部品を⽤意(Scheduler) その間へ差し込む層には既存FW等のコードもそ のまま使える(←とても重要)
Slide 14
Slide 14 text
実験的にDoctrine ORMの⾮同期版を作る試み amphp/mysqlとamphp/green-threadを利⽤ https://github.com/joelwurtz/doctrine-async
Slide 15
Slide 15 text
説明⽤のよくある表 説明⽤のよくある表 プロセス OSスレッド Fiber メモリ空間 分離 共有 共有 タイムスライスで 切り替え あり あり なし I/Oブロックで 切り替え あり あり なし ⽣成コスト 重い 中くらい 軽い 切り替えコスト 重い 中くらい 軽い 複数コア利⽤ できる できる だめ
Slide 16
Slide 16 text
RFCの現状 RFCの現状 ⽅針の固まってない部分がある RFCが少し⼝ベタ
Slide 17
Slide 17 text
ASYNC/AWAIT? ASYNC/AWAIT? async/await欲しいよね https://github.com/fiberphp/fiber-ext/issues/10
Slide 18
Slide 18 text
Promiseのような⾮同期データ取得の抽象化まで ⼿を出すのは話がデカすぎ Future Scope送りに https://github.com/fiberphp/fiber-ext/issues/31
Slide 19
Slide 19 text
マシンスタックの扱い マシンスタックの扱い 現状実装はVMスタックのみ切り替え array_map()等の C → PHPで抜けられない やろうとしたら例外を⾶ばす
Slide 20
Slide 20 text
$f = new Fiber(function () { return array_map(function ($i) { return Fiber::yield($i); // 例外飛ばす }, ['a', 'b']); });
Slide 21
Slide 21 text
マシンスタック(Cスタック)も切り替えるPR Pros: どっからでもyieldで抜けられる Cons: ポータビリティが失われる メモリ消費量が増える https://github.com/fiberphp/fiber-ext/pull/30
Slide 22
Slide 22 text
オリジナル版の⾜りないところ オリジナル版の⾜りないところ C → PHPでのFiber::yieldをいつでも避けられる か、というとそうでもない 既存FWの利⽤時も何気なく発⽣ call_user_func()系とか怪しい PHPUnitも\ReflectionMethod::invokeArgs()とか finallyが今のところちゃんと動いてない
Slide 23
Slide 23 text
MARTIN版の⾜りないところ MARTIN版の⾜りないところ PHP処理系は動作環境を明⾔してない ポータブルでない何かをコアへ⼊れるのは⼤変 そう︖ 「必要な時だけCスタック確保」は難しく、メモ リも多めに確保せざるを得ない
Slide 24
Slide 24 text
解決策を緩く募集
Slide 25
Slide 25 text
PHPでFIBER何うれしい︖ PHPでFIBER何うれしい︖ PHP単体でサーバとかマイクロサービスみたいな のが作りやすくなる ErlangとかAkkaみたいなActorもやりやすめに なるよ︕
Slide 26
Slide 26 text
PTHREADS拡張どうよ PTHREADS拡張どうよ PHPでスレッドを使えるものの、扱いがめんどい pthreads拡張はZTSにもとづいてるため、スレ ッド間で基本はデータが共有されない 静的プロパティ等の扱いに癖があり、既存FW 等の資産が使いづらい印象 癖への対処法が確⽴されていればよいが、利 ⽤例もあまり⾒つからない
Slide 27
Slide 27 text
FORKしたらいいんじゃね︕ FORKしたらいいんじゃね︕ プロセスで済むならプロセスでも別にいい プロセスは重め、データ共有も⾟いめ
Slide 28
Slide 28 text
PHPでやらなきゃいいんじゃ︖ PHPでやらなきゃいいんじゃ︖ そんな野暮なことを⾔わない︕ できないよりできた⽅が楽しいでしょ︕
Slide 29
Slide 29 text
動作原理 動作原理
Slide 30
Slide 30 text
実⾏コンテキスト 実⾏コンテキスト Fiberは実⾏コンテキストを差し替えて動く 実⾏コンテキストとは︖ マシンが次に何を実⾏するか、その次に何を 実⾏するか……を定める状態 メモリとCPUのレジスタ状態でだいぶ表せる
Slide 31
Slide 31 text
メモリについて メモリについて CPUが扱う命令/データを⼊れとく場所 1バイトのデータ⼊れる箱がたくさん並んでるイ メージ
Slide 32
Slide 32 text
CPUについて CPUについて CPUはメモリ上の機械語/データを解釈して実⾏ PCやIPと呼ばれるレジスタを持つ 「今メモリ上のどこを実⾏してます」を指す 1つ命令を⾷っては次の番地の命令、と動く
Slide 33
Slide 33 text
ジャンプ ジャンプ 「次の番地の命令」以外へPCを動かす ちょっと前の番地へジャンプすればループに 「データの状態がAなら指定番地へジャンプ、そ うでなければ次の番地に進む」的な分岐命令も
Slide 34
Slide 34 text
C関数呼び出し C関数呼び出し 次のPCの値をどこかに保存 よくあるのはスタック 関数の命令列の先頭へジャンプ returnで保存しておいた元の番地へ戻る
Slide 35
Slide 35 text
スタック スタック コンピュータ⽤語、FILOのデータ構造を指す データをぽんぽん突っ込めて、突っ込んだのと 逆順に取り出してなかったことにできる
Slide 36
Slide 36 text
マシンスタック マシンスタック 多くのCPUはメモリ領域のどこかをスタックとし て扱う命令を持つ これのためにスタックの現在位置を指すレジス タ(SP︓スタックポインタ)がある
Slide 37
Slide 37 text
C⾔語ではよく関数の戻りアドレスの他、ローカ ル変数もスタックに保存
Slide 38
Slide 38 text
実⾏コンテキストはスタック 実⾏コンテキストはスタック に︖ に︖ 各実⾏コンテキストで別々のスタックを持つよ うにする PC/IPとSPを含むCPUのレジスタを保存、別コン テキストのを復帰してジャンプ できた︕コンテキストスイッチできた︕単純︕
Slide 39
Slide 39 text
PHPではもう⼀⼯夫要る
Slide 40
Slide 40 text
VMスタック VMスタック PHPコードは処理系によりVMのオペコードにコ ンパイルされて実⾏
Slide 41
Slide 41 text
PHPのVMはマシンスタックと別にVM独⾃のスタ ックを持つ VMスタックも切り替える必要がある
Slide 42
Slide 42 text
というか、実はPHPの世界だけならVMスタック だけ切り替えればよい PHP Fiberのオリジナル実装はコレ PHP処理系は通常のPHP関数呼び出しで再帰的な VM呼び出しをせず、実マシンでいうPC変更に相 当する挙動(opline切り替え)のみ⾏い、オペコ ードを1つ1つループで取り出して実⾏
Slide 43
Slide 43 text
問題はPHP -> C -> PHPのような呼び出しでCの世 界での実⾏コンテキストも保存が必要なケース
Slide 44
Slide 44 text
オリジナル実装はvm_interruptという機構を利⽤ オペコード1つ実⾏するごとに処理系が割り込 みフラグを確認し、⽴ってれば割り込みハン ドラを呼び出すような仕組み 割り込みハンドラ内でVMの実⾏状態を切り替 えて復帰 martin版はswapcontextまたはインラインアセン ブラのジャンプで素直にコンテキスト⼊れ替え
Slide 45
Slide 45 text
まとめ︓がんばってほしい まとめ︓がんばってほしい 「Node.js使え」「Go使え」的な⾯⽩みのない話 に負けないでほしい ⾯⽩いのでみんなも触ってみてほしい
Slide 46
Slide 46 text
おしまい おしまい