Upgrade Guide 1.5
Please back up before upgrading and execute the following commands to upgrade
composer require workerman/webman-framework ^1.5 -W && composer require webman/console ^1.2.12 && php webman install
Features and Changes
Support for workerman v5 Fiber
Note
workerman v5 requires PHP>=8.1
Workerman upgrade commandcomposer require workerman/workerman ^5.0.0 -W
Fiber coroutines need to installcomposer require revolt/event-loop ^1.0.0
Example
Delayed Response
<?php
namespace app\controller;
use support\Request;
use Workerman\Timer;
class TestController
{
public function index(Request $request)
{
// Sleep for 1.5 seconds
Timer::sleep(1.5);
return $request->getRemoteIp();
}
}
Timer::sleep()
is similar to the sleep()
function in PHP, but the difference is that Timer::sleep()
does not block the process.
Making HTTP Requests
Note
Requires installation of 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'); // Synchronously initiates an asynchronous request
return $response->getBody()->getContents();
}
}
Similarly, the $client->get()
request is non-blocking, which can be used to handle HTTP requests non-blockingly in webman, improving performance.
For more information, refer to workerman/http-client
Addition of support\Context class
The support\Context class is used to store request-related data, and when the request is completed, the corresponding context data is automatically deleted. This means that the context data lifecycle follows the request lifecycle.
Global Variable Pollution
In a coroutine environment, it is prohibited to store request-related status information in global variables or static variables, as this may cause global variable pollution, for example:
<?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;
}
}
When the number of processes is set to 1, if we make two consecutive requests:
http://127.0.0.1:8787/test?name=lilei
http://127.0.0.1:8787/test?name=hanmeimei,
we expect the results of the two requests to be lilei
and hanmeimei
respectively, but in reality, both return hanmeimei
.
This is because the second request overwrites the static variable $name
, so when the first request's sleep ends and returns, the static variable $name
has already become hanmeimei
.
The correct method is to use context to store request status data
<?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');
}
}
Local variables do not cause data pollution
<?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;
}
}
Because $name
is a local variable, coroutines cannot access local variables from each other, so using local variables is coroutine safe.
About Coroutines
Coroutines are not a silver bullet. Introducing coroutines means that you need to pay attention to the global variable/static variable pollution issue and set the context context. Additionally, debugging bugs in a coroutine environment is more complex than in blocking programming.
Webman's blocking programming is already fast enough. According to techempower.com benchmark data from the last three rounds over the last three years, webman's blocking programming with database business is nearly twice as fast as Go's web framework gin, echo, and nearly 40 times faster than traditional framework Laravel.
When the database and Redis are both on the intranet, the performance of multi-process blocking programming may often be higher than that of coroutines. This is because when the database and Redis are fast enough, the overhead of coroutine creation, scheduling, and destruction may be greater than the overhead of process switching, so introducing coroutines in this case may not significantly improve performance.
When to Use Coroutines
When there are slow accesses in the business, such as when the business needs to access third-party interfaces, you can use workerman/http-client to initiate asynchronous HTTP calls in a coroutine manner to improve the application's concurrency capability.