May 14, 2021 Swoole
Swoole starts at 2.0 with the built-in co-program
(Coroutine) capability,
which provides a co-program capability
Swoole\Coroutine\*
PHP7 is supported for 2.0.2 or later
Co-programs can be understood as user-only threads that switch through collaboration rather than preesting. A ll co-program operations can be done in the user state, compared to a process or thread, and it is less expensive to create and switch. Swoole can create a corresponding co-program for each request, which can reasonably schedule the co-program based on the state of the IO, which brings the following advantages:
Developers can achieve asynchronous IO effects and performance without the perception of synchronous code writing, avoiding the discrete code logic brought about by traditional asynchronous callbacks and getting stuck in multiple layers of callbacks that make the code unresponsible.
At the same time, because swoole is encapsulated in the underlying co-program, so compared to the traditional php-layer co-program framework, developers do not need to use yield keywords to identify a co-program IO operation, so there is no need for a deep understanding of yield semantics and every level of the call is modified to yield, which greatly improves development efficiency.
Co-program APIs are currently available in packages for mainstream protocols such as TCP, UDP, including:
To meet the needs of most developers. For private protocols, developers can use co-program TCP or UDP interfaces for convenient encapsulation.
swoole_server
swoole_http_server
onRequet
only supported in
onReceive
onConnect
event callback functions.
swoole 2.0 needs to enable co-program capability by adding
--enable-coroutine
compilation parameters, as follows:
phpize
./configure --with-php-config={path-to-php-config} --enable-coroutine
make
make install
Add the compilation parameters and the swoole server switches to co-program mode.
When co-program mode is
swoole_server
swoole_http_server
will create a corresponding co-program for each request, and developers can use co-program clients in the
onRequet
onReceive
onConnect
3 event callbacks.
Add a configuration parameter max_coro_num to the set method of
Swoole\Server
max_coro_num
configure the maximum number of co-programs processed by a worker process at the same time.
Because as the number of co-programs processed by the worker process increases, so does the memory it consumes, to avoid exceeding the memory_limit limit
memory_limit
set this value based on the actual business pressure measurement results, which defaults to 3000.
When the code
connect()和recv()
swoole triggers a co-switch, at which point the swoole can handle other events or accept new requests. W
hen this connection
连接
or the back-end service returns the package, the swoole server resumes the co-program context and the code logic continues to resume execution from the switching point.
回包
T
he developer does not need to care about the entire switching process.
Use documents that you can refer to.
__call()
dereferencing pointer ‘v.327’ does break strict-aliasing rules
dereferencing type-punned pointer will break strict-aliasing rules
manually edit Makefile, replace
CFLAGS = -Wall -pthread -g -O2
with
CFLAGS = -Wall -pthread -g -O2 -fno-strict-aliasing
make
make clean;make;make install
bool getDefer();
bool setDefer([bool $is_defer = true]);
mixed recv();
In the co-program version of, multiple client-side conceding capabilities are implemented.
Typically, if a business request requires a redis request and a mysql request, the network IO will look like this:
redis发包->redis收包->mysql发包->mysql收包
The time of the above process network IO is equal to the redis network IO time and mysql network IO time.
For the co-program version of Client, network IO can be like this:
redis发包->mysql发包->redis收包->mysql收包
The above process network IO time is close to MAX (redis network IO time, mysql network IO time).
Clint, which now supports 2007 requests, has:
With the exception of Swoole, Coroutine, client, all other Clients implement the defer feature, which is used to declare deferred packages.
Because the sending and receiving methods of Swoole/Coroutine/Client are separate, there is no need to implement the defer feature, while the other Clint's packages and receipts are in one method, so a setDefer() method is required to declare the deferred collection, and then through the recv() method.
Co-program version of Client concentred request sample code:
<?php
$server = new Swoole\Http\Server("127.0.0.1", 9502, SWOOLE_BASE);
$server->set([
'worker_num' => 1,
]);
$server->on('Request', function ($request, $response) {
$tcpclient = new Swoole\Coroutine\Client(SWOOLE_SOCK_TCP);
$tcpclient->connect('127.0.0.1', 9501,0.5)
$tcpclient->send("hello world\n");
$redis = new Swoole\Coroutine\Redis();
$redis->connect('127.0.0.1', 6379);
$redis->setDefer();
$redis->get('key');
$mysql = new Swoole\Coroutine\MySQL();
$mysql->connect([
'host' => '127.0.0.1',
'user' => 'user',
'password' => 'pass',
'database' => 'test',
]);
$mysql->setDefer();
$mysql->query('select sleep(1)');
$httpclient = new Swoole\Coroutine\Http\Client('0.0.0.0', 9599);
$httpclient->setHeaders(['Host' => "api.mp.qq.com"]);
$httpclient->set([ 'timeout' => 1]);
$httpclient->setDefer();
$httpclient->get('/');
$tcp_res = $tcpclient->recv();
$redis_res = $redis->recv();
$mysql_res = $mysql->recv();
$http_res = $httpclient->recv();
$response->end('Test End');
});
$server->start();
Swoole 2.0 is
setjmp
longjmp
which automatically saves the memory state of the Zend VM (primarily EG global memory and vm stack) when co-switching.
$server = new Swoole\Http\Server('127.0.0.1', 9501, SWOOLE_BASE);
#1
$server->on('Request', function($request, $response) {
$mysql = new Swoole\Coroutine\MySQL();
#2
$res = $mysql->connect([
'host' => '127.0.0.1',
'user' => 'root',
'password' => 'root',
'database' => 'test',
]);
#3
if ($res == false) {
$response->end("MySQL connect fail!");
return;
}
$ret = $mysql->query('show tables', 2);
$response->end("swoole response is ok, result=".var_export($ret, true));
});
$server->start();
onRequest
event callback function is
coro_create
Create a covage (# 1 position) And Saves Both The CPU Register Status and zendvm stack information at this point in time.
mysql->connect
is called,
coro_save
save the state of the current co-program, including the Zend VM context and co-program description
coro_yield
Give Control of The Program, And The Current Request Is Suspended (# 2 location)
core_resume
The Corresponding Co-Program, RESTORES The Zendvm Context, And Continues Down The PHP Code (# 3 Location)
mysql->query
performs in the same way as
mysql->connect
and also performs a co-program switching schedule
end
method to return the result and destroy the co-program
Co-programs add extra memory footprint than normal asynchronous callback programs.
Ubuntu16.04 + Core I5 4核 + 8G内存 PHP7.0.10
ab -c 100 -n 10000 http://127.0.0.1:9501/
Test results:
Server Software: swoole-http-server
Server Hostname: 127.0.0.1
Server Port: 9501
Document Path: /
Document Length: 348 bytes
Concurrency Level: 100
Time taken for tests: 0.883 seconds
Complete requests: 10000
Failed requests: 168
(Connect: 0, Receive: 0, Length: 168, Exceptions: 0)
Total transferred: 4914560 bytes
HTML transferred: 3424728 bytes
Requests per second: 11323.69 [#/sec] (mean)
Time per request: 8.831 [ms] (mean)
Time per request: 0.088 [ms] (mean, across all concurrent requests)
Transfer rate: 5434.67 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.2 0 2
Processing: 0 9 9.6 6 96
Waiting: 0 9 9.6 6 96
Total: 0 9 9.6 6 96
Percentage of the requests served within a certain time (ms)
50% 6
66% 9
75% 11
80% 12
90% 19
95% 27
98% 43
99% 51
100% 96 (longest request)