Руководство по обновлению до версии 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, чтобы увеличить возможности параллелизма приложения.