Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

PHP 8 で Web 以外の世界の扉を叩く

2,893 views

Published on

PHP カンファレンス 2020 の発表資料

本番で使ったものにスタイルの修正 / リンクの追加など若干の手直しを入れています
本番でうまくデモが動かなかったので、後から録画を幾つか上げています
https://twitter.com/sji_ch/status/1337774274606555141
https://twitter.com/sji_ch/status/1337690042165149697
https://twitter.com/sji_ch/status/1337693697907933186

Published in: Technology
  • Be the first to comment

PHP 8 で Web 以外の世界の扉を叩く

  1. 1. PHP 8 でWEB 以外の世界の扉 を叩く 五⼗嵐進⼠/ sji / sj-i / @sji_ch
  2. 2. ⾃⼰紹介 ⽣まれも育ちも仙台 株式会社インフィニットループ仙台⽀社 スマートフォンゲームのサーバサイドのプログラマ
  3. 3. PHP カンファレンス仙台とかやった
  4. 4. 去年娘ができた
  5. 5. AGENDA なぜPHP 7.5 ではなく8 なのかJIT FFI PHP での並列並⾏処理課題とまとめ
  6. 6. デモ
  7. 7. タガヤスでちょっと話した タガヤスという仙台の勉強会イベントで少し解説した スライドも公開してるので興味があれば https://tagayas.connpass.com/event/193881/ https://www.slideshare.net/shinjiigarashi/php-239601300
  8. 8. 対象プロセス上での処理系の内部データのメモリアドレスを特定
  9. 9. 対象プロセス上での処理系の内部データのメモリアドレスを特定 PHP で処理系のバイナリデータをパース
  10. 10. 対象プロセス上での処理系の内部データのメモリアドレスを特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース
  11. 11. 対象プロセス上での処理系の内部データのメモリアドレスを特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース FFI でシステムコールを呼んで対象プロセスのメモリを覗き⾒
  12. 12. 対象プロセス上での処理系の内部データのメモリアドレスを特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース FFI でシステムコールを呼んで対象プロセスのメモリを覗き⾒ 処理系の内部データ構造を解釈してコールトレースを抜き出す
  13. 13. 解析スレッド 対象プロセス上での処理系の内部データのメモリアドレスを 特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース FFI でシステムコールを呼んで対象プロセスのメモリを覗き⾒ 処理系の内部データ構造を解釈してコールトレースを抜き出 す
  14. 14. 解析スレッド 対象プロセス上での処理系の内部データのメモリアドレスを 特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース FFI でシステムコールを呼んで対象プロセスのメモリを覗き⾒ 処理系の内部データ構造を解釈してコールトレースを抜き出 す 集計出⼒スレッド
  15. 15. 解析スレッド 対象プロセス上での処理系の内部データのメモリアドレスを 特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース FFI でシステムコールを呼んで対象プロセスのメモリを覗き⾒ 処理系の内部データ構造を解釈してコールトレースを抜き出 す 集計出⼒スレッド コールトレースの集計をとる
  16. 16. 解析スレッド 対象プロセス上での処理系の内部データのメモリアドレスを 特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース FFI でシステムコールを呼んで対象プロセスのメモリを覗き⾒ 処理系の内部データ構造を解釈してコールトレースを抜き出 す 集計出⼒スレッド コールトレースの集計をとる FFI でGUI のウィンドウを描画
  17. 17. ⾮同期通信+ Preloading + でマルチスレッド 解析スレッド 対象プロセス上での処理系の内部データのメモリアドレス を特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース FFI でシステムコールを呼んで対象プロセスのメモリを覗 き⾒ 処理系の内部データ構造を解釈してコールトレースを抜き 出す 集計出⼒スレッド FFI でGUI のウィンドウを描画 コールトレースの集計をとる JIT
  18. 18. ⾮同期通信+ Preloading + でマルチスレッド 解析スレッド 対象プロセス上での処理系の内部データのメモリアドレス を特定 PHP で処理系のバイナリデータをパース Linux のプロセス情報ファイルをパース FFI でシステムコールを呼んで対象プロセスのメモリを覗 き⾒ 処理系の内部データ構造を解釈してコールトレースを抜き 出す 集計出⼒スレッド FFI でGUI のウィンドウを描画 コールトレースの集計をとる JIT
  19. 19. なぜPHP 7.5 ではなくPHP 8 = PHP 2^3 なのか
  20. 20. 可能性1 互換性が崩れたから?
  21. 21. 可能性1 互換性が崩れたから? SemVer でもメジャーバージョン更新はAPI の互換性が崩れる時
  22. 22. 可能性1 互換性が崩れたから? SemVer でもメジャーバージョン更新はAPI の互換性が崩れる時 互換性を崩す機能を⼊れるためのPHP8 ?
  23. 23. 可能性1 互換性が崩れたから? SemVer でもメジャーバージョン更新はAPI の互換性が崩れる時 互換性を崩す機能を⼊れるためのPHP8 ? ちがうと思う!
  24. 24. RFC PHP の開発プロセスはRFC にもとづく ⼤きな機能追加や変更、プロジェクトのルール変更で必要 コミュニティで議論の上、投票で採否を決める
  25. 25. RFC 作成⽇ Shorter Attribute Syntax Change 2020- 08-04 Don't automatically unserialize Phar metadata outside getMetadata() 2020- 07-07 Reclassifying engine warnings 2019- 08-27 Ensure correct signatures of magic methods 2020- 04-05
  26. 26. RFC 作成⽇ Named Arguments 2020-05-05 Treat namespaced names as single token 2020-06-15 Saner string to number comparisons 2019-02-26 Saner numeric strings 2020-06-28
  27. 27. RFC 作成⽇ Remove inappropriate inheritance signature checks on private methods 2020- 04-16 Match expression v2 2020- 05-22 Attribute Amendments 2020- 05-11 Make sorting stable 2020- 05-12
  28. 28. RFC 作成⽇ Locale-independent oat to string cast 2020-03- 11 Change Default PDO Error Mode 2020-03- 28 Stricter type checks for arithmetic/bitwise operators 2020-04- 02 Add str_starts_with() and str_ends_with() functions 2020-03- 25
  29. 29. RFC 作成⽇ Validation for abstract trait methods 2020-02- 07 Add Stringable interface 2020-01- 15 Implement new DOM Living Standard APIs in ext/dom 2019-09- 15 Arrays starting with a negative index 2017-04- 20
  30. 30. RFC 作成⽇ Consistent type errors for internal functions 2019-02-05
  31. 31. PHP 8.0 ⽤のブランチは2019 年1 ⽉ に出てる php-master-changes 2019-01-28 https://qiita.com/sj-i/items/418282051c3c647e7aed#nikic- clear-news-upgrading-and-upgradinginternals
  32. 32. ほとんどのRFC が出た時にはPHP 8 が出るのは決まってた 後⽅互換性が崩れる変更を⼊れたいからメジャーバージョンアッ プ、ではない メジャーバージョンが上がるからそういう変更が⼊っている メジャーバージョンアップ⾃体は何か別の要因
  33. 33. 可能性2 規定のリリーススケジュー ルによるもの
  34. 34. 可能性2 規定のリリーススケジュー ルによるもの 何年おきか決まったスケジュールで定期的にメジャーバージョン を上げている?
  35. 35. 可能性2 規定のリリーススケジュー ルによるもの 何年おきか決まったスケジュールで定期的にメジャーバージョン を上げている? 4 年おきとか5 年おきとか
  36. 36. 可能性2 規定のリリーススケジュー ルによるもの 何年おきか決まったスケジュールで定期的にメジャーバージョン を上げている? 4 年おきとか5 年おきとか いや、これでもない
  37. 37. メジャーバージョンリリース遍歴 バージョン リリース⽇ PHP 1 1995 年6 ⽉8 ⽇ PHP 2 1997 年11 ⽉1 ⽇ PHP 3 1998 年6 ⽉6 ⽇ PHP 4 2000 年5 ⽉22 ⽇ PHP 5 2004 年7 ⽉13 ⽇ PHP 7 2015 年12 ⽉3 ⽇
  38. 38. メジャーバージョンリリース遍歴 バージョン リリース⽇ PHP 1 1995 年6 ⽉8 ⽇ PHP 2 1997 年11 ⽉1 ⽇ PHP 3 1998 年6 ⽉6 ⽇ PHP 4 2000 年5 ⽉22 ⽇ PHP 5 2004 年7 ⽉13 ⽇ PHP 7 2015 年12 ⽉3 ⽇ 全然定期的ではない
  39. 39. リリースプロセスについてもRFC はあるが Yearly release cycle というのは決まっている メジャーバージョンをいつ上げる、という話は特にない https://wiki.php.net/rfc/releaseprocess
  40. 40. 可能性3 処理系の内部エンジンが⼤ きく変わったから? バージョン 内部エンジンのバージョン PHP 4 Zend Engine PHP 5 Zend Engine 2 PHP 7 Zend Engine 3
  41. 41. 可能性3 処理系の内部エンジンが⼤ きく変わったから? バージョン 内部エンジンのバージョン PHP 4 Zend Engine PHP 5 Zend Engine 2 PHP 7 Zend Engine 3 実際にはこれでもない
  42. 42. PHP 8 は内部的なエンジン変更は⼩さい Dmitry ⼤先⽣も⼤したことないって⾔ってる https://externals.io/message/112291#112295 PHP 8.0 didn't introduce revolutionary engine changes (like PHP 7 and PHP 5 did)
  43. 43. じゃあなんでPHP 8 が出たの?
  44. 44. JIT です!
  45. 45. ⾊々なものが決まる場所 INTERNALS PHP のコア開発者による開発⽅針の議論は主にML 今は詳細な実装⽅針についてはGitHub でのやり取りも php-internals というもの 単にinternals と呼ばれることも多い externals.io というサイトでWeb からも⾒れる
  46. 46. "PHP 8 NEXT?" 2018 年6 ⽉に、コア開発者のnikita さんがinternals に投稿 「次のバージョンPHP 8 になりそうな雰囲気を感じてるんだけ ど、実際どうなの?」というメール https://externals.io/message/102378
  47. 47. ZEEV さんのありがたいお⾔葉
  48. 48. ZEEV さんのありがたいお⾔葉 ユーザへ⼤きな影響を与えるような⼤変更こそがメジャーバージ ョンに値する
  49. 49. ZEEV さんのありがたいお⾔葉 ユーザへ⼤きな影響を与えるような⼤変更こそがメジャーバージ ョンに値する ユーザにとって⼤きなリターンが得られる変更があるからこそ、 それに伴う後⽅互換性の破壊も正当化され得る
  50. 50. ZEEV さんのありがたいお⾔葉 ユーザへ⼤きな影響を与えるような⼤変更こそがメジャーバージ ョンに値する ユーザにとって⼤きなリターンが得られる変更があるからこそ、 それに伴う後⽅互換性の破壊も正当化され得る 例えばJIT やFFI、⾮同期処理や⻑時間実⾏スクリプトのサポー ト
  51. 51. PHP 2^3 Zeev さんが話の流れに乗ってML へ投下した8 への意気込みメ ール https://externals.io/message/102415
  52. 52. PHP 2^3 Zeev さんが話の流れに乗ってML へ投下した8 への意気込みメ ール https://externals.io/message/102415 次のメジャーバージョンではJIT やFFI、⾮同期処理や⻑時間実 ⾏スクリプトのサポートやpreloading の機能を盛り込みたい
  53. 53. PHP 2^3 Zeev さんが話の流れに乗ってML へ投下した8 への意気込みメ ール https://externals.io/message/102415 次のメジャーバージョンではJIT やFFI、⾮同期処理や⻑時間実 ⾏スクリプトのサポートやpreloading の機能を盛り込みたい 7.3 のリリース後はPHP 8 に向けて開発⼒を集中したい
  54. 54. PHP 2^3 Zeev さんが話の流れに乗ってML へ投下した8 への意気込みメ ール https://externals.io/message/102415 次のメジャーバージョンではJIT やFFI、⾮同期処理や⻑時間実 ⾏スクリプトのサポートやpreloading の機能を盛り込みたい 7.3 のリリース後はPHP 8 に向けて開発⼒を集中したい 7.4 は8 の準備で廃⽌予定機能⾮推奨化オンリーのスリムなリリ ースに
  55. 55. その結果どうなったか
  56. 56. PHP 7.4 の新機能(の⼀部) 型付プロパティ アロー関数 variance(反変/ 共変)のサポート FFI Preloading
  57. 57. PHP 7.4 の新機能(の⼀部) 型付プロパティ アロー関数 variance(反変/ 共変)のサポート FFI Preloading 全然スリムじゃないね!
  58. 58. 「次はPHP 8」は残った 2018 年11 ⽉、Nikita さんから"Branch off PHP-7.4 early" とい うメールがintenals へ 早めに7.4 のブランチ切ってmaster へ8 向けの作業を⼊れて いけるようにする提案
  59. 59. 「次はPHP 8」は残った 2018 年11 ⽉、Nikita さんから"Branch off PHP-7.4 early" とい うメールがintenals へ 早めに7.4 のブランチ切ってmaster へ8 向けの作業を⼊れて いけるようにする提案 2019 年1 ⽉28 に実際にPHP 7.4 のブランチが切られる
  60. 60. 「次はPHP 8」は残った 2018 年11 ⽉、Nikita さんから"Branch off PHP-7.4 early" とい うメールがintenals へ 早めに7.4 のブランチ切ってmaster へ8 向けの作業を⼊れて いけるようにする提案 2019 年1 ⽉28 に実際にPHP 7.4 のブランチが切られる 同⽇にJIT のRFC ページが作られる
  61. 61. 「次はPHP 8」は残った 2018 年11 ⽉、Nikita さんから"Branch off PHP-7.4 early" とい うメールがintenals へ 早めに7.4 のブランチ切ってmaster へ8 向けの作業を⼊れて いけるようにする提案 2019 年1 ⽉28 に実際にPHP 7.4 のブランチが切られる 同⽇にJIT のRFC ページが作られる この段階でFFI とPreloading はPHP 7.4 向けで受理済
  62. 62. 次のメジャーバージョンへ⼊れよう と話されていたもの JIT FFI Preloading ⾮同期処理のサポート ⻑時間実⾏スクリプトのサポート
  63. 63. 次のメジャーバージョンへ⼊れよう と話されていたもの JIT FFI Preloading
  64. 64. 次のメジャーバージョンへ⼊れよう と話されていたもの JIT FFI Preloading
  65. 65. 次のメジャーバージョンへ⼊れよう と話されていたもの JIT ←これしか残ってない FFI Preloading
  66. 66. PHP 8 のためのJIT のためのPHP 7.4 の機能 JIT 実装はLuaJIT を参考にしたもの FFI もJIT との組み合わせを念頭に置きつつLuaJIT にもとづいて 提案 Preloading もJIT / FFI との組み合わせも念頭に置きつつ提案 まだ完全な姿ではないがコマは揃ってきた
  67. 67. PHP 8 のビジョン Zend / Dmitry さんの7 年以上に渡る取り組みの成果がJIT とそ の周辺機能 既存のアプリケーションでさほどの性能向上が⾒られないと分か っていたにも関わらず断⾏された 何か強い明確なビジョンがある
  68. 68. PHP 8 のビジョン Zend / Dmitry さんの7 年以上に渡る取り組みの成果がJIT とそ の周辺機能 既存のアプリケーションでさほどの性能向上が⾒られないと分か っていたにも関わらず断⾏された 何か強い明確なビジョンがある つまり既存のPHP アプリケーションの枠内にはないことをやれ るようになること!
  69. 69. WEB 以外の世界の扉を叩く
  70. 70. JIT
  71. 71. ここでデモ 以前⻑⾕川さん(@tomzohさん)がPHP のファミコンエミュレー タを公開 PHPで動くファミコンエミュレータを作った JIT の有無での差を⾒る https://www.hasegawa-tomoki.com/blog/2018/10/16/php- terminal-nes-emulator/
  72. 72. CPU バウンドな処理はJIT 向き JIT なしが14 FPS くらい JIT あり(tracing JIT)が35 FPS くらい JIT が得意な処理なので2.5 倍くらい差が出る
  73. 73. TRACING JIT と関数JIT JIT にはtracing JIT とfunction JIT のモードがある opcache.jit で切り替え デフォルトはtracing JIT こっちの⽅がたいてい速い、中⾝は少し複雑 2019 年1 ⽉のRFC 当時はまだなかった 2020 年3 ⽉頃に⼊った
  74. 74. ⼿をかければもっと速くできる プロファイラでボトルネックを特定し最適化 https://github.com/sj-i/php-terminal-nes-emulator
  75. 75. ⼿動最適化対応の例 ループ外に出せる処理を出したり フレームバッファでRGB が別れてるのを1 つの整数値にパック して扱ったり 計算結果をキャッシュしたり定数化したり 型宣⾔を外したり ひたすら泥臭い奴できちんと効果が出る
  76. 76. ⼿動最適化対応の例 ループ外に出せる処理を出したり フレームバッファでRGB が別れてるのを1 つの整数値にパック して扱ったり 計算結果をキャッシュしたり定数化したり 型宣⾔を外したり ひたすら泥臭い奴できちんと効果が出る 逆に⾔うと処理系はそんなに頑張ってない
  77. 77. ⼿動最適化の結果まとめ JIT なし: 静⽌状態で約50 FPS、画⾯が動きはじめると約35 FPS JIT あり: 静⽌状態で約85 FPS、画⾯が動きはじめると約60 FPS JIT 有無での差は1.7 倍程度に
  78. 78. ⼿動最適化の結果まとめ JIT なし: 静⽌状態で約50 FPS、画⾯が動きはじめると約35 FPS JIT あり: 静⽌状態で約85 FPS、画⾯が動きはじめると約60 FPS JIT 有無での差は1.7 倍程度に JIT で速くなる計算処理⾃体が減ったため?
  79. 79. JIT についての現況まとめ CPU バウンドな処理はやはり速くなる、1.7 倍とか2.5 倍とか tracing JIT とfunction JIT でも1.5 倍程度の差が出るケースも まだまだ「⼈間が適当に書いても処理系が最適化してくれる」の 世界ではない ⼈間がしょぼい対応で速くする余地がある、JIT の今後の伸びし ろもありそう
  80. 80. FFI
  81. 81. FFI とは Foregin Function Interface の略 直訳すると外国語の関数のインターフェース C ⾔語の関数やデータへアクセスできる機能 PHP 7.4 で導⼊された
  82. 82. FFI 導⼊以前 7.3 までのPHP はできないことが多かった 標準関数の範囲外はC の拡張機能が必要 実際は標準関数⾃体も処理系に標準添付された拡張という形 拡張を作るには処理系の特殊な作法と⼀定以上のC ⾔語知識が 必要
  83. 83. FFI 導⼊以降 C ⾔語資産をPHP から直接呼べる システムコールやメモリ操作の関数、処理系の内部関数など など 当然リスクも⼀緒に持ち込まれる PHP 処理系内部の深い知識、拡張を書く際の特有の作法は不要 C ⾔語の知識は必要
  84. 84. FFI の使い⽅$ffi = FFI::cdef( 'int printf(const char * restrict format, ... );', // 'libc.so' /* libc は処理系とともに読み込まれているので不要 */ ); $ffi->printf('hello clang world');
  85. 85. FFI の使いみち PHP 単体ではできないことをやる 低レイヤの機能への直接アクセス PHP 側資産とくらべてC ⾔語資産が豊富な分野 PHP 単体で出せる以上の速度が欲しい時 FFI のオーバヘッドには要注意
  86. 86. システムコール OS の機能を呼び出すための仕組み これまでのPHP はWeb に特化した⾔語で、標準で全ての機能に アクセスすることはできない 例えばioctl() でデバイスを直接操作するとか 例えばptrace() やprocess_vm_readv() を使って別プロセスの挙 動を覗き⾒るとか php-pro ler はコレを利⽤
  87. 87. PHP の処理系⾃⾝を操作する PHP の処理系は拡張向けにC ⾔語API を提供 FFI からも呼び出せる 処理系の挙動をFFI 越しにカスタマイズすることも可能
  88. 88. PHP と演算⼦オーバーロード PHP スクリプト内では各演算⼦の挙動を変更することはできな い 実はC ⾔語拡張からは演算⼦の挙動を変更したクラスを作れ る、DateTime やGMP などが利⽤ FFI 経由で処理系の拡張向けAPI にアクセスすればPHP 内から も実現可能
  89. 89. FFI から演算⼦オーバーロードしてみる Z-Engine を利⽤ class A {} $refClass = new ReflectionClassEx(A::class); $handler = Closure::fromCallable([ObjectCreateTrait::class, '__init']); $refClass->setCreateObjectHandler($handler); $refClass->setCompareValuesHandler(fn (...$args) => 0); var_dump(new A() == 1); // true になる var_dump(new A() == 'string'); // true になる
  90. 90. Z-ENGINE FFI を通じてPHP 処理系の内部機能へアクセスするためのライ ブラリ ライセンスがRPL 1.5 で少し縛りが強い PHP による演算⼦オーバーロード Re ection からの nal 外し https://github.com/lisachenko/z-engine
  91. 91. GUI 伝統的スタイルのGUI プログラムもFFI から利⽤可能 ウィンドウを開いたりメニューを描画したり、ボタンを押した時 に動くコールバックを登録したり
  92. 92. GTK クロスプラットフォームなGUI ツールキット 元々はGimp のために作られ、現在はGnome のツールキットと して使われている Windows にも移植されている。 https://www.gtk.org/
  93. 93. TOKNOT/GTK FFI でのgtk バインディングの⼀つ windows にも対応 https://github.com/chopins/php-gtk
  94. 94. TOKNOT/GTK FFI でのgtk バインディングの⼀つ windows にも対応 https://github.com/chopins/php-gtk ⼿元のubuntu ではちょっといじったら動いた https://github.com/sj-i/php-gtk
  95. 95. GTK でPHP からウィンドウを作る include __DIR__ . '/../vendor/autoload.php'; const PHP_GTK_DEV_DEBUG = false; $gtk = PHPGtk::gtk(); $gtk->gtk_init($argc, $argv); $mainwin = $gtk->gtk_window_new(GtkGtkEnum::GTK_WINDOW_TOPLEVEL); $gtk->gtk_widget_show_all($mainwin); $gtk->gtk_main();
  96. 96. GTK でPHP からボタン押下時のコールバックを使う こんなコード追加だけでいける $button = $gtk->gtk_button_new_with_label('button'); $callback = function () { echo 'hello'; }; $gtk->g_signal_connect($button, 'clicked', $gtk->G_CALLBACK($callback), null); $gtk->gtk_container_add($gtk->GTK_CONTAINER($window), $button);
  97. 97. GLADE で作ったUI も使える Glade というGTK のGUI デザイナがある Glade で作ったUI データもPHP から使える https://glade.gnome.org/
  98. 98. 「PHP FFI」でGITHUB で検索 SFML SDL libpcap opencv https://github.com/djuhnix/phpml https://github.com/Sera mArts/f -sdl https://github.com/rtckit/php-pcap-f https://github.com/ghostjat/php_opencv
  99. 99. VULKAN のバインディングも https://github.com/BicEngine/Vulkan
  100. 100. SDL のデモ ファミコンエミュレータの描画にSDL を使ってみる ふつうに動く 画⾯に⾊がつくよ! https://github.com/Sera mArts/f -sdl
  101. 101. PHP による並列処理
  102. 102. THE FREE LUNCH WAS OVER 今どきのCPU はマルチコア、4 以上のコアも当たり前になって きた JIT でシングルスレッド性能を上げるだけでは⾜りない
  103. 103. PHP のマルチスレッド PHP はスレッドセーフではないので、マルチスレッドのプログ ラムは作れない PHP でスレッドを使うことはできるが、Python やRuby のよう にGIL がある
  104. 104. PHP のマルチスレッド PHP はスレッドセーフではないので、マルチスレッドのプログ ラムは作れない PHP でスレッドを使うことはできるが、Python やRuby のよう にGIL がある どっちも誤解だよ!
  105. 105. ZTS(ZEND THREAD SAFETY) PHP 4 の頃からあるスレッドセーフ版処理系 IIS などのマルチスレッド動作するWeb サーバへ組み込むための 機構 スレッドごとに処理系の内部状態を別々に持つような仕組み
  106. 106. ZTS によるスレッド拡張 ZTS はWeb サーバでのリクエスト処理の⼟台で使う仕組み PHP スクリプトからスレッドを作るためのAPI は提供されてい ない 拡張でZTS にもとづきスレッド機能を提供するものが存在 有名なのはpthreads
  107. 107. EXT-PTHREADS PHP Threads の略 POSIX スレッドの単なるラッパーではない どちらかというとJava っぽい雰囲気のAPI 作者はkrakjoe (Joe Watkins) さん phpdbg やpcov やapcu の作者でもある 2019 年に開発中⽌、PHP 7.4 以降への対応はしない→parallel へ https://github.com/krakjoe/pthreads
  108. 108. EXT-PARALLEL pthreads のkrakjoe さんの新作スレッド拡張 現在最も有⼒なマルチスレッド拡張 https://github.com/krakjoe/parallel
  109. 109. PARALLEL の使い⽅ <?php $runtime = new parallelRuntime(); $future = $runtime->run(function(){ for ($i = 0; $i < 500; $i++) echo "*"; return "easy"; }); for ($i = 0; $i < 500; $i++) { echo "."; } printf("nUsing parallelRuntime is %sn", $future->value());
  110. 110. 別スレッドのグローバル変数が⾒えない $global_variable = '⾒える'; $runtime = new parallelRuntime(); $future = $runtime->run(function(){ global $global_variable; return $global_variable ?? '⾒えない'; }); printf("別スレッドのグローバル変数は", $future->value());
  111. 111. データ⾮共有モデル ZTS にもとづく拡張ではスレッド間は互いに隔離 グローバル変数やクラス変数は各スレッドで異なる値を持ち 得る PHP はshared-nothing あるリクエストの処理から別のリクエストの変数を⾒たり触れた りはできない プロセスでもスレッドでも同じ状況を作るのがZTS
  112. 112. CHANNEL $channel = new parallelChannel(); $runtime = new parallelRuntime(); $future = $runtime->run( function(parallelChannel $channel){ $message = $channel->recv(); echo $message; }, [$channel] ); $channel->send('message');
  113. 113. データ⾮共有は制限ではなくメリット メモリ共有で通信するな、通信でメモリを共有しろ と、parallel のPHP マニュアルのPhilosophy でも書いてある https://www.php.net/manual/ja/philosophy.parallel.php
  114. 114. ZEND のND の⼈だって⾔っている Zend のnd の⽅の⼈も昔同じようなことを⾔っていた もしスレッドを実装するとしたら、⼀番良いの はそれぞれが⾃前のコンテキストを持ったワー カースレッドを⽣成できるようにして、データ 共有はしない(だからロックも要らない)奴だ ろうね。そしてスレッド間でメッセージパッシ ングするAPI を提供する。-- Andy Gutmans ( )https://externals.io/message/47701#47729
  115. 115. 他⾔語でも近いノリの話がある D ⾔語はデフォルトでスレッド間のデータが⾮共有 ただしimmutable なデータは共有できる The D Programming Language という本にちょっと載ってる https://www.informit.com/articles/article.aspx?p=1609144 http://dusers.dip.jp/modules/wiki/?Articles%2FTDPL%20- %20Concurrency%20in%20D%2F1
  116. 116. なぜPARALLEL が⽣まれたのか https://blog.krakjoe.ninja/2019/02/parallel-php-next- chapter.html While aware, there was nothing driving me to write another API, until recently when Zend made their intention to merge the JIT they have been working on for years into PHP. Just think for a moment what it would mean to be able to execute machine code in parallel in user land PHP ...
  117. 117. なぜPARALLEL が⽣まれたのか: 訳 pthreads と別の並列処理API を作りたい、みたいなのはしばら くなかった Zend の⼈たちが年⽉を費やして作ってきたJIT のマージに向け て動くまではね ちょっと考えてみてほしい これはつまりユーザランドのPHP によって機械語のコードを並 列実⾏できるってことだよね?
  118. 118. 本当は共有したいデータ(コード)もある parallel でのデータ⾮共有は変数だけではなく、コードも同じ あるリクエストで定義したクラスが別のリクエストからは読めな いのと同じ スレッドごとにブートストラップコストが必要になる スレッド⽣成の実質的な鈍⾜化
  119. 119. PRELOADING とPARALLEL ここでpreloading preloading は実はCLI でも利⽤できる 各スレッドで共有メモリ上の同じクラス定義を使い回せる
  120. 120. PARALLEL を使ったライブラリ amphp-parallel reactphp-parallel https://github.com/amphp/parallel https://github.com/reactphp-parallel/reactphp-parallel
  121. 121. JIT + PARALLEL のデモ 再度ファミコンエミュレータを改修 描画スレッドとCPU / PPU で描画する内容を計算するスレッド を分ける 前のフレームを描画しきる前に描画内容の計算が終わった場合、 そのフレームの描画をスキップ
  122. 122. JIT + PARALLEL のデモ 再度ファミコンエミュレータを改修 描画スレッドとCPU / PPU で描画する内容を計算するスレッド を分ける 前のフレームを描画しきる前に描画内容の計算が終わった場合、 そのフレームの描画をスキップ JIT だと計算スレッドが300 FPS くらい出る
  123. 123. ⾮同期処理も組み合わせる
  124. 124. PHP-PROFILER のデーモンモード 正規表現でPHP プロセスのコマンドパターンを指定しておく マッチするプロセスを⾒つけてきては勝⼿にアタッチしてトレー スを出⼒ 3 種類のスレッドが動作 処理対象を探す探査スレッド コールトレースを取得する解析スレッド それらの振り分けと出⼒をやるメインスレッド
  125. 125. メインスレッドを⽌めないようコルーチン メインスレッドが他スレッドと通信する際などブロックしてほし くない amphp でコルーチンを各ワーカースレッドごとに⽤意 Generator ベースのコルーチンでも案外戦えるという印象
  126. 126. AMPHP + PSALM ⼩話 実はpsalm にamphp をサポートする機能@psalm-yieldというも のがあり、Promise に付いてる Promise<T>をyield するとTが返ってくるものとして型解析 本当はamphp のループ外で使ったら別の値が来るかもしれな い、のだが、そこは無視
  127. 127. 現状の課題
  128. 128. JIT は発展途上 速くはなってもJIT エンジン界ではまだまだ新参者 The Computer Language Benchmarks の多くのベンチマークでま だNode には結構負けてる PHP 8 の今後に期待 tracing JIT 導⼊(約1 年)での性能向上実績もある https://benchmarksgame- team.pages.debian.net/benchmarksgame/fastest/php.html
  129. 129. スレッドもまだ発展途上 Union サポートが完全ではない opcache.jit=1205 + preload じゃないとSEGV 起こしたり opcache.jit=1205 + preload でもSEGV 起こすケースも krakjoe さんを応援しよう! Patreon もGitHub スポンサーもあるよ! https://www.patreon.com/krakjoe
  130. 130. FFI もまだ発展途上 LuaJIT で⼊ってるようなC を越えるレベルの最適化はまだない When FFI Function Calls Beat Native C でもそのうち⼊る筈、PHP でもC に勝てる⽇が来るか? https://nullprogram.com/blog/2018/05/27/
  131. 131. 公式の⾮同期サポートはまだ amphp のtrowski さんが3 代⽬Fiber RFC に最近取り組んでる かつて頓挫したFiber RFC の落胤であるext-async の後継 8.x へのコア⼊りを⽬指している筈 https://github.com/amphp/ext- ber
  132. 132. まとめ
  133. 133. PHP とPHPER の進化 PHP 4 にはまともなオブジェクト指向機能さえなかった 今は成熟したオブジェクト指向機能もあれば静的型検査のエコシ ステムもある PHP プログラマもこれらの機能に習熟してきた Web なら「それPHP でもできるし、PHP で別にいいじゃない」 と⾔える
  134. 134. PHP とPHPER の新たな挑戦 PHP でFFI もマルチスレッドも⾮同期処理もある程度できるよ うになってきた JIT まで⼊った ⾔語とエコシステムとしては準備が整ってきている しかしPHP プログラマの⽅はどうか 「Web 以外だってPHP でも別にいいじゃない」と⾔えるのか
  135. 135. 変なことをやりましょう!
  136. 136. おしまい

×