Руководство по обновлению до версии 1.5

Перед обновлением сделайте резервную копию, выполните следующие команды для обновления:
composer require workerman/webman-framework ^1.5 -W && composer require webman/console ^1.2.12 && php webman install

Функциональные особенности и изменения

Поддержка корутина (Fiber) workerman v5

Примечание
workerman v5 требует PHP>=8.1
Команда обновления workerman: composer require workerman/workerman ^5.0.0 -W
Для корутины (Fiber) необходимо установить: 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() подобен встроенной функции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(), является неблокирующим, что позволяет обрабатывать HTTP-запросы в 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, когда мы отправляем два последовательных запроса
http://127.0.0.1:8787/test?name=lilei
http://127.0.0.1:8787/test?name=hanmeimei
Мы ожидаем, что результаты двух запросов будут соответственно lilei и hanmeimei, но фактически оба возвращают hanmeimei.
Это происходит потому, что второй запрос перезаписывает статическую переменную $name, а к моменту завершения первого запроса статическая переменная $name уже равна hanmeimei.

Правильным подходом будет использование контекста для хранения данных состояния запроса

<?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, webman в обработке бизнес-логики с базой данных примерно в 1,5 раза превосходит производительность веб-фреймворка gin и echo на языке Go, и примерно в 40 раз выше производительность традиционного фреймворка Laravel.

Когда база данных и Redis находятся во внутренней сети, производительность многопроцессной блокирующей программы часто оказывается выше, чем у корутин, потому что дополнительные расходы на создание, планирование и уничтожение корутин могут быть больше, чем расходы на переключение процессов, когда база данных, Redis и прочие устройства достаточно быстры, введение корутин может не привести к значительному увеличению производительности.

Когда использовать корутины

Когда в бизнес-логике имеются медленные запросы, например, когда бизнес требует доступа к стороннему API, можно воспользоваться асинхронным вызовом HTTP с использованием workerman/http-client, чтобы увеличить возможности параллелизма приложения.