setDefer 机制
绝大部分协程组件,都支持了setDefer
特性。可以将请求响应式的接口拆分为两个步骤,使用此机制可以实现先发送数据, 再并发收取响应结果。
由于大多数情况下, [建立连接和发送数据的耗时] 相比于 [等待响应的耗时] 来说可以忽略不计, 所以可以简单理解为defer模式下, 多个客户端的请求响应是并发的
以HttpClient
为例,设置setDefer(true)
后,发起$http->get()
请求,将不再等待服务器返回结果,而是在send request
之后,立即返回true
。在此之后可以继续发起其他HttpClient
、MySQL
、Redis
等请求。最后再使用$http->recv()
接收响应内容。
相比子协程 + Channel
的实现方式,setDefer
更简单一些。
需注意的是, defer特性只支持并发收取响应结果, 正如示例代码所示, 创建连接和数据的发送, 仍是串行的
示例代码
<?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();