1.5 アップグレードガイド

バックアップを取った後、次のコマンドを実行してアップグレードします
composer require workerman/webman-framework ^1.5 -W && composer require webman/console ^1.2.12 && php webman install

機能の特性と変更

workerman v5のcoroutineをサポートしています

ヒント
workerman v5 は PHP>=8.1 が必要です
workermanアップグレードコマンド composer require workerman/workerman ^5.0.0 -W
Fiber coroutine を使用するためには composer require revolt/event-loop ^1.0.0 をインストールする必要があります

サンプル

遅延応答

<?php

namespace app\controller;

use support\Request;
use Workerman\Timer;

class TestController
{
    public function index(Request $request)
    {
        // 1.5秒待機
        Timer::sleep(1.5);
        return $request->getRemoteIp();
    }
}

Timer::sleep() はPHPのsleep() 関数と似ていますが、Timer::sleep() はプロセスをブロックしません

HTTPリクエストの発行

注意
composer require workerman/http-client ^2.0.0 をインストールする必要があります

<?php

namespace app\controller;

use support\Request;
use Workerman\Http\Client;

class TestController
{
    public function index(Request $request)
    {
        static $client;
        $client = $client ?: new Client();
        $response = $client->get('http://example.com'); // 同期的に非同期リクエストを行う
        return $response->getBody()->getContents();
    }
}

同様に$client->get()のリクエストはブロックされず、これによりwebmanで非同期リクエストを処理することができ、パフォーマンスが向上します。

詳細についてはworkerman/http-clientを参照してください。

support\Context クラスの追加

support\Context クラスは、リクエストに関連するデータを保存するために使用され、リクエストが完了すると、対応するコンテキストデータは自動的に削除されます。つまり、コンテキストデータのライフサイクルはリクエストのライフサイクルに従います。

グローバル変数の汚染

コルーチン環境では、リクエストに関連する状態情報をグローバル変数や静的変数に保存しないでください。なぜなら、これはグローバル変数の汚染を引き起こす可能性があるからです。例えば

<?php

namespace app\controller;

use support\Request;
use Workerman\Timer;

class TestController
{
    protected static $name = '';

    public function index(Request $request)
    {
        static::$name = $request->get('name');
        Timer::sleep(5);
        return static::$name;
    }
}

プロセス数を1に設定し、連続して2つのリクエストを行った場合
http://127.0.0.1:8787/test?name=lilei
http://127.0.0.1:8787/test?name=hanmeimei
期待される結果はそれぞれ lileihanmeimei ですが、実際の結果は hanmeimei です。
これは、2つ目のリクエストが静的変数$nameを上書きしたためです。最初のリクエストが完了すると、静的変数$nameは既にhanmeimeiになっているからです。

正しい方法は、リクエスト状態のデータをcontextに保存することです

<?php

namespace app\controller;

use support\Request;
use support\Context;
use Workerman\Timer;

class TestController
{
    public function index(Request $request)
    {
        Context::set('name', $request->get('name'));
        Timer::sleep(5);
        return Context::get('name');
    }
}

ローカル変数はデータの汚染を引き起こしません

<?php

namespace app\controller;

use support\Request;
use support\Context;
use Workerman\Timer;

class TestController
{
    public function index(Request $request)
    {
        $name = $request->get('name');
        Timer::sleep(5);
        return $name;
    }
}

$name はローカル変数であるため、コルーチン間でローカル変数を参照することはできません。したがって、ローカル変数の使用はコルーチンの安全性を保証します。

コルーチンについて

コルーチンは銀の弾丸ではありません。コルーチンを導入すると、グローバル変数/静的変数の汚染に注意する必要があり、コンテキストを設定する必要があります。さらに、コルーチン環境でのバグのデバッグは、ブロック式プログラミングよりもやや複雑になります。

webmanのブロック式プログラミングは実際には十分に速く、techempower.comの最近の3年間のベンチマークデータによると、webmanのブロック式プログラミングはデータベースビジネスにおいてgoのwebフレームワークginやechoなどよりほぼ倍のパフォーマンスを持ち、伝統的なフレームワークlaravelよりも約40倍の高性能を示しています。

データベースやredisがすべて内部ネットワーク上にある場合、多プロセスのブロック式プログラミングの性能はしばしばコルーチンの導入よりも高くなります。なぜならば、データベースやredisなどが十分に速い場合、コルーチンの作成、スケジューリング、破棄のオーバーヘッドがプロセスの切り替えのオーバーヘッドよりも大きくなる可能性があるからです。そのため、このような場合には、コルーチンを導入してもパフォーマンスの向上がそれほど大きくないことが多いです。

いつコルーチンを使用するか

業務で遅いリクエストがある場合、例えば、ビジネスがサードパーティのAPIにアクセスする必要がある場合、workerman/http-clientを使用して非同期HTTP呼び出しを行うことで、アプリケーションの並行能力を向上させることができます。