検索

失敗した PHP 拡張機能開発の旅

By warezhou 2014.11.19


Origin

継続的な反復の後、私たちの部門のコルーチンバージョンネットワークフレームワーク(CoSvr)フレーム)がついにリリースされました!これは元々は素晴らしいことでしたが、新しいサービスが継続的にアクセスされるにつれて、多くの固有の欠陥が徐々に表面化しました。 「過負荷保護」をサポートしていません

「ホットリスタート」をサポートしていません

  • 「64ビット」をサポートしていません
  • ... ...
  • 上級バックエンド開発者にとって、上記の問題はほとんどのそれらを識別するのは難しく、それらが問題になる理由は、「カエルをお湯でゆでる」ようなものです。反復プロセスにはマクロなビジョンが欠けており、導入されるビジネス機能が多すぎるため、全体的なアーキテクチャが不合理になります。最近の「コルーチン バージョン」は、元々は私の個人的なアマチュア作品で、ビジネス コードを楽しく書き、作業をすぐに終了するために、最下層はオリジナルの SvrFrame を直接再利用しました。結果はご想像のとおり、基盤が強力ではありません。大地が揺れる!最も極端な 64Bit を例に挙げると、誰もが数秒で理解できると思います。
  • 多くの調査と議論を経て、最終的に次のような方向性を出しました:
  • 社内オープンソース SPP3.0 フレームワークを導入し、基本的な周辺機能を吸収し、二次的なビジネス開発を行う

    SPP を拡張し、PHP をサポートする埋め込みプログラミング用のスクリプト言語であり、C 拡張機能の形で PHP にコルーチン機能を提供します (今後、PHPer は非同期コードを喜んで作成できるようになり、母はもう私のコールバックについて心配する必要がなくなりました!)

    難しい? 長くなりましたが、本題に入りましょう: C++/PHP 混合プログラミングを実装するにはどうすればよいでしょうか?

  • 免責事項:
  • 私は途中の修道士なので、丸一週間 PHP 拡張機能の開発に携わっていないため、「WHY」については触れず、「HOW」については記録目的のみにとどめることができれば幸いです。専門家なら許してくれるでしょう!
  • オープニング

    組み込み

    PHP 業界における C++/PHP の組み合わせは一般に「パフォーマンス」の考慮事項に基づいており、特定のパフォーマンスのボトルネック (PB シリアル化など) を解決するために PHP コード内で C/C++ 拡張機能を呼び出します。 )。

    C/C++ 開発者としては、「パフォーマンス」よりも「開発効率」の誘惑が明らかに大きいため、私たちのアイデアは、PHP をスクリプト言語として使用して、ビジネス ロジックを迅速に開発し、それを SPP フレームワークに挿入して実行することです。 。

    1. RTLD_GLOBAL モードで PHP ダイナミック ライブラリを開きます

    void *php_handler = dlopen("libphp5.so", RTLD_LAZY | RTLD_GLOBAL);if (!php_handler) {    base->log_.LOG_P_PID(LOG_FATAL, "%s\n", dlerror());    return -1; }   dlclose(php_handler);

    2. php_embed_init を通じて初期化します

    php_embed_module.php_ini_path_override = "../php/php.ini";php_embed_init(0, NULL);

    3. zend_eval_string は PHP スクリプトを導入します

    すごいです

    4. call_user_function による PHP 関数のコールバック

    zend_first_try {    char exec_str[256];    snprintf(exec_str, sizeof(exec_str), "include '%s';", "../php/demo_handler.php");    if (int ret = zend_eval_string(exec_str, NULL, exec_str TSRMLS_CC)) {        base->log_.LOG_P_PID(LOG_FATAL, "zend_eval_string fail. ret=%d\n", ret);        return -1;     }    base->log_.LOG_P_PID(LOG_DEBUG, "zend_eval_string succ.\n");} zend_catch {    base->log_.LOG_P_PID(LOG_FATAL, "zend_eval_string catch.\n");} zend_end_try ();

    5. php_embed_shutdown によるクリーンアップ

    zval z_funcname;ZVAL_STRING(&z_funcname, "EchoDemo::init", 1);zval *zp_svr;MAKE_STD_ZVAL(zp_svr);ZVAL_LONG(zp_svr, (long)base);zval *zp_etc;MAKE_STD_ZVAL(zp_etc);ZVAL_STRING(zp_etc, etc, 1);zval z_retval;zval *z_params[] = {zp_svr, zp_etc};int call_ret = call_user_function(CG(function_table), NULL, &z_funcname, &z_retval, sizeof(z_params) / sizeof(z_params[0]), z_params TSRM convert_to_long(&z_retval);int func_ret = Z_LVAL_P(&z_retval);zval_ptr_dtor(&zp_etc);zval_dtor(&z_funcname);zval_dtor(&z_retval);if (call_ret log_.LOG_P_PID(LOG_FATAL, "call_user_function fail. call_ret=%d func_ret=%d\n", call_ret, func_ret);    return -1;}

    PHP

    PHP C 拡張機能の開発に関する記事はインターネット上にあります。興味のある読者は記事末尾の付録を詳しく読んでみてください。

    1. PHP ソース コード パッケージをダウンロードし、手動でコンパイルします。上記の組み込み使用と連携するには、?enable-embed オプション

    php_embed_shutdown(TSRMLS_C);

    2 をオンにする必要があります。 PHP ソース コード パッケージの ext ディレクトリに入り、ext_skel ツールがプラグイン シェルフ コードを生成します

    ./configure --enable-embedmakemake install(可选)

    3. config.m4 を編集し、PHP_ARG_WITH または PHP_ARG_ENABLE オプションをオンにします (正直に言うと、違いはまだ明確ではありません。アドバイスをお願いします)、C++ サポート、依存関係パスなどを追加します。

    cd ext./ext_skel --extname=demo

    4.demo.cpp を編集し、拡張定義と実装 (関数、クラス、変数など) を追加します。 ) ここに挙げるのは関数定義の例だけです。クラスに興味のある読者は、付録に従って調べてください。ここで示した sendrecv 関数の定義は比較的代表的なもので、3 番目のパラメーター rsp は、受信したデータを PHP 呼び出し元に返す責任があります

    PHP_ARG_ENABLE(demo, whether to enable demo support,    [  --enable-demo           Enable demo support])if test "$PHP_DEMO" != "no"; then  PHP_REQUIRE_CXX()  PHP_ADD_LIBRARY(stdc++, 1, EXTRA_LDFLAGS)  PHP_ADD_INCLUDE(/root/spp/module/include/)  PHP_ADD_INCLUDE(/root/spp/module/include/spp_incl/)  PHP_NEW_EXTENSION(demo, demo.cpp, $ext_shared)fi
    ZEND_BEGIN_ARG_INFO_EX(arginfo_sendrecv, 0, 0, 7)    ZEND_ARG_INFO(0, req)    ZEND_ARG_INFO(0, req_len)    ZEND_ARG_INFO(1, rsp)    ZEND_ARG_INFO(0, rsp_len)    ZEND_ARG_INFO(0, ip)    ZEND_ARG_INFO(0, port)    ZEND_ARG_INFO(0, timeout)ZEND_END_ARG_INFO()PHP_FUNCTION(sendrecv){    char *req = NULL;    int req_str_len = 0;    long req_len = 0;    zval *rsp = NULL;    long rsp_len = 0;    char *ip = NULL;    int ip_str_len = 0;    long port = 0;    long timeout = 0;if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "slzlsll", &req, &req_str_len,&req_len, &rsp, &rsp_len, &ip, &ip_str_len, &port, &timeout) == FAILURE) {        return;}       struct sockaddr_in addr;    memset(&addr, 0, sizeof(addr));    addr.sin_family = AF_INET;    addr.sin_addr.s_addr = inet_addr(std::string(ip, ip_str_len).c_str());    addr.sin_port = htons(port);    char *rsp_buf = (char *)emalloc(rsp_len);    int rsp_buf_len = rsp_len;    if (int ret = mt_udpsendrcv(&addr, req, req_len > req_str_len ? req_str_len : req_len, rsp_buf, rsp_buf_len, timeout)) {        efree(rsp_buf);        RETURN_LONG(ret);    }    zval_dtor(rsp);    ZVAL_STRINGL(rsp, rsp_buf, rsp_buf_len, 0);    RETURN_LONG(0);}

    5。私は個人的には動的コンパイルを好みます (静的コンパイルには php ソース コードの再コンパイルが必要ですが、これは非常に時間がかかり、手間がかかります)。 6. php.ini ファイルを編集し、新しい拡張機能を追加すると、PHP コードで新しい拡張機能を呼び出すことができます

    クライマックス

    いよいよ、EchoDemo をいくつかプレイしてみました。 telnetとsaw エコーが一行ずつ表示されるので非常に気持ちいいです。

    const zend_function_entry demo_functions[] = {    PHP_FE(sendrecv, arginfo_sendrecv)    PHP_FE_END  /* Must be the last line in demo_functions[] */};

    ここで最も優れているのは、プロセス関数の sendrecv への拡張呼び出しです。非同期ネットワーク インタラクションは、バックグラウンドでコルーチンを介して実装されています。同期 CGI のようなロジック コードを作成できるだけでなく、それを簡単に楽しむこともできます。非同期の高い同時実行性。

    願いは美しいけど現実は残酷!

    私は突然アイデアを思いつきました。パフォーマンスのストレス テストを行って、ネイティブ C++ コードと比較してどの程度パフォーマンスが低下するかを確認してみましょう。 1KB の単一リクエストが適用され、1w/s の圧力が適用されました。しばらくすると、コアダンプが抑制されました。

    メモリリーク?コルーチンスタックオーバーフロー? ...

    期間中色々紆余曲折あり、GDB、コルーチンのスタックサイズ変更、Google、PHPerの相談…

    すぐに夜になり、確認すべきことは確認した、質問は全て完了それは尋ねる必要がありますが、私にできることは何もありません。わかりました。お茶を飲みに立ち寄ってください。「call_user_function は再入可能ですか?」このレベルを考えると、コルーチンの性質を理解している兄弟ならすぐに理解できると思います。「くそー、Zend を実装するとき、呼び出し元のスレッドがユーザー モード スケジューリングのためにコルーチンを実行することをどのようにして知ることができるのでしょうか。これではすべてが可能です。」ブラックボックス。 !グローバル変数、静的変数...

    さて、sendrecv などのコルーチンベースの拡張機能を削除して、テストを再負荷します。単一のワーカーは、ストレスなく 3w/s のエコーを処理できます。

    エンディング

    今回の最大の魅力の一つは結局実現には至りませんでしたが、考えることは一人で行動するよりも100倍効率的であるという視点を改めて確認できたのでとても満足しています

    特に難しい問題に対処する場合、頭のないハエが飛び回るのは報われないことがよくあります。このとき、落ち着いて既存の知識の蓄えを収集することに全力を尽くすことができれば、もしかしたらインスピレーションが訪れるかもしれません。

    今後の可能性のある方向性: PHP はバージョン 5.5 から yield を導入しました。Zend の yield サポートの詳細を掘り下げれば、それを C フレームワークとうまく統合できるかもしれないと感じていますが、これには大きな穴があるといつも感じています。それは埋めることができません。他の要因を差し置いても、私はやはり Golang のような言語を選択して goroutine の利点を直接享受したいと思うかもしれません (笑)。 付録

    PHP 拡張機能の開発とカーネル アプリケーション

    http://www.walu.cc/phpbook/preface.md

    PHP 拡張機能をコンパイルする 2 つの方法

    http://521-wf.com/archives/ 227 .html

    C++ を使用して PHP 拡張機能を開発する方法 (パート 1)

    http://521-wf.com/archives/241.html

    C++ を使用して PHP 拡張機能を開発する方法 (パート 2)

    http ://521-wf.com/archives/245.html

    PHP 拡張機能での C++ クラスのラップ


    http://devzone.zend.com/1435/wrapping-c-classes-in-a-php-extension /

    🎜
    声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
    トラフィックの高いウェブサイトのPHPパフォーマンスチューニングトラフィックの高いウェブサイトのPHPパフォーマンスチューニングMay 14, 2025 am 12:13 AM

    thesecrettokeepingaphp-poweredwebsterunningsmootlyunderheavyloadinvolvesseveralkeystrategies:1)emform opcodecoduceSciptionexecutiontime、2)aatabasequerycachingwithiThing withiThistolessendavasoload、

    PHPでの依存関係注射:初心者向けのコード例PHPでの依存関係注射:初心者向けのコード例May 14, 2025 am 12:08 AM

    コードをより明確かつ維持しやすくするため、依存関係が関心(DI)に注意する必要があります。 1)DIは、クラスを切り離すことにより、よりモジュール化されます。2)テストとコードの柔軟性の利便性を向上させ、3)DIコンテナを使用して複雑な依存関係を管理しますが、パフォーマンスの影響と円形の依存関係に注意してください。

    PHPパフォーマンス:アプリケーションを最適化することは可能ですか?PHPパフォーマンス:アプリケーションを最適化することは可能ですか?May 14, 2025 am 12:04 AM

    はい、最適化されたAphPossibleandessention.1)CachingingusapCutoredatedAtabaseload.2)最適化、効率的なQueries、およびConnectionPooling.3)EnhcodeCodewithBultinctions、Avoididingglobalbariables、およびUsingopcodeching

    PHPパフォーマンスの最適化:究極のガイドPHPパフォーマンスの最適化:究極のガイドMay 14, 2025 am 12:02 AM

    keyStrategIestsoSificlyvoostphpappliceperformanceare:1)useopcodecachinglikeToreexecutiontime、2)最適化abaseの相互作用とプロペラインデックス、3)3)構成

    PHP依存性噴射コンテナ:クイックスタートPHP依存性噴射コンテナ:クイックスタートMay 13, 2025 am 12:11 AM

    aphpDependencyInjectionContaineriSATOULTAINATINAGECLASSDEPTINCIES、強化測定性、テスト可能性、および維持可能性。

    PHPの依存噴射対サービスロケーターPHPの依存噴射対サービスロケーターMay 13, 2025 am 12:10 AM

    SELECT DEPENTENCINGINOFCENT(DI)大規模なアプリケーションの場合、ServicElocatorは小さなプロジェクトまたはプロトタイプに適しています。 1)DIは、コンストラクターインジェクションを通じてコードのテスト可能性とモジュール性を改善します。 2)ServiceLocatorは、センター登録を通じてサービスを取得します。これは便利ですが、コードカップリングの増加につながる可能性があります。

    PHPパフォーマンス最適化戦略。PHPパフォーマンス最適化戦略。May 13, 2025 am 12:06 AM

    phpapplicationscanbeoptimizedforspeedandEfficiencyby:1)enabingopcacheinphp.ini、2)PreparedStatementswithpordatabasequeriesを使用して、3)LoopswithArray_filterandarray_mapfordataprocessing、4)の構成ngincasaSearverseproxy、5)

    PHPメールの検証:電子メールが正しく送信されるようにしますPHPメールの検証:電子メールが正しく送信されるようにしますMay 13, 2025 am 12:06 AM

    PHPemailvalidationinvolvesthreesteps:1)Formatvalidationusingregularexpressionstochecktheemailformat;2)DNSvalidationtoensurethedomainhasavalidMXrecord;3)SMTPvalidation,themostthoroughmethod,whichchecksifthemailboxexistsbyconnectingtotheSMTPserver.Impl

    See all articles

    ホットAIツール

    Undresser.AI Undress

    Undresser.AI Undress

    リアルなヌード写真を作成する AI 搭載アプリ

    AI Clothes Remover

    AI Clothes Remover

    写真から衣服を削除するオンライン AI ツール。

    Undress AI Tool

    Undress AI Tool

    脱衣画像を無料で

    Clothoff.io

    Clothoff.io

    AI衣類リムーバー

    Video Face Swap

    Video Face Swap

    完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

    ホットツール

    SublimeText3 中国語版

    SublimeText3 中国語版

    中国語版、とても使いやすい

    WebStorm Mac版

    WebStorm Mac版

    便利なJavaScript開発ツール

    ゼンドスタジオ 13.0.1

    ゼンドスタジオ 13.0.1

    強力な PHP 統合開発環境

    SublimeText3 Linux 新バージョン

    SublimeText3 Linux 新バージョン

    SublimeText3 Linux 最新バージョン

    ドリームウィーバー CS6

    ドリームウィーバー CS6

    ビジュアル Web 開発ツール