Swoole-2.0 提供了PHP原生协程调度器,PHP代码可以按照同步方式编写,底层引擎使用异步IO,调度器会在IO完成后自动切换PHP函数调用栈。
内置协程不依赖PHP的Yield/Generator语法,实现了真正的同步代码,异步IO。Swoole-2.0兼容Swoole-1.0所有现存特性,同时支持同步阻塞、异步非阻塞回调、协程 3 种 IO 模型。
协程可以理解为用户态线程,通过协作而不是抢占来进行切换。相对于操作系统进程或者线程,协程所有的操作都可以在用户态完成,创建和切换的消耗更低。Swoole可以为每一个请求创建对应的协程,根据IO的状态来合理地调度协程。
Swoole-2.0内置协程的优势:
Callback Hell
。yield
,这极大的提高了开发效率。goroutine
+chan
+select
才能实现。Swoole-2.0的并发调用使用更加简单。Swoole\Coroutine\Client
Swoole\Coroutine\HttpClient
Swoole\Coroutine\Redis
Swoole\Coroutine\MySQL
Swoole\Server
或者Swoole\Http\Server
进行开发,目前仅支持在onRequet
、onReceive
、onConnect
回调中使用协程Swoole-2.0需要通过添加--enable-coroutine
编译参数启用协程能力,示例如下:
phpize./configure --with-php-config={path-to-php-config} --enable-coroutinemake
make install
添加编译参数,swoole server将切换到协程模式
TCP协程客户端
$client = new Swoole\Coroutine\Client(SWOOLE_SOCK_TCP);$client->connect('127.0.0.1', 9501,0.5)//调用connect将触发协程切换$client->send("hello world\n");
echo $client->recv();//调用recv将再次触发协程切换$client->close();
Http协程客户端
$cli = new Swoole\Coroutine\Http\Client('127.0.0.1', 80);$cli->setHeaders([ 'Host' => "localhost", "User-Agent" => 'Chrome/49.0.2587.3', 'Accept' => 'text/html,application/xhtml+xml,application/xml', 'Accept-Encoding' => 'gzip',
]);$cli->set([ 'timeout' => 1]);$cli->get('/index.php');echo $cli->body;$cli->close();
$redis = new Swoole\Coroutine\Redis();$redis->connect('127.0.0.1', 6379);$val = $redis->get('key');
MySQL协程客户端
$swoole_mysql = new Swoole\Coroutine\MySQL();$swoole_mysql->connect(['host' => '127.0.0.1',
'user' => 'user', 'password' => 'pass',
'database' => 'test',
]);$res = $swoole_mysql->query('select sleep(1)');
并发调用
$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();
通常,如果一个业务请求中需要做一次redis请求和一次mysql请求,那么网络IO会是这样:
redis发包->redis收包->mysql发包->mysql收包
以上流程网络IO的时间就等于 redis网络IO时间 + mysql网络IO时间。
而对于协程版本的Client,网络IO可以是这样:
redis发包->mysql发包->redis收包->mysql收包
以上流程网络IO的时间就接近于 MAX(redis网络IO时间, mysql网络IO时间)。
现在支持并发请求的Client有:
除了Swoole\Coroutine\Client
,其他Client都实现了defer特性,用于声明延迟收包。
__destruct()
__call()