当前位置:K88软件开发文章中心编程语言PHPSwoole → 文章内容

Swoole Coroutine协程支持

减小字体 增大字体 作者:佚名  来源:网上搜集  发布时间:2019-1-15 15:55:04

由 路飞 创建, 最后一次修改 2017-01-03 Swoole在2.0开始内置协程(Coroutine)的能力,提供了具备协程能力IO接口(统一在名空间Swoole\Coroutine\*)。2.0.2或更高版本已支持PHP7协程可以理解为纯用户态的线程,其通过协作而不是抢占来进行切换。相对于进程或者线程,协程所有的操作都可以在用户态完成,创建和切换的消耗更低。Swoole可以为每一个请求创建对应的协程,根据IO的状态来合理的调度协程,这会带来了以下优势:开发者可以无感知的用同步的代码编写方式达到异步IO的效果和性能,避免了传统异步回调所带来的离散的代码逻辑和陷入多层回调中导致代码无法维护。同时由于swoole是在底层封装了协程,所以对比传统的php层协程框架,开发者不需要使用yield关键词来标识一个协程IO操作,所以不再需要对yield的语义进行深入理解以及对每一级的调用都修改为yield,这极大的提高了开发效率。协程API目前针对了TCP,UDP等主流协议client的封装,包括:UDPTCPHTTPMysqlRedis可以满足大部分开发者的需求。对于私有协议,开发者可以使用协程的TCP或者UDP接口去方便的封装。启用Prerequisite:PHP版本要求:>= 5.5,包括5.5、5.6、7.0、7.1基于swoole_server或者swoole_http_server进行开发,目前只支持在onRequet, onReceive, onConnect事件回调函数中使用协程。swoole2.0需要通过添加--enable-coroutine编译参数启用协程能力,示例如下:phpize./configure --with-php-config={path-to-php-config} --enable-coroutinemakemake install添加编译参数,swoole server将切换到协程模式。开启协程模式后,swoole_server和swoole_http_server将以为每一个请求创建对应的协程,开发者可以在onRequet、onReceive、onConnect 3个事件回调中使用协程客户端。相关配置在Swoole\Server的set方法中增加了一个配置参数max_coro_num,用于配置一个worker进程最多同时处理的协程数目。因为随着worker进程处理的协程数目的增加,其占用的内存也会增加,为了避免超出php的memory_limit限制,请根据实际业务的压测结果设置该值,默认为3000。使用示例$client = new Swoole\Coroutine\Client(SWOOLE_SOCK_TCP);$client->connect("127.0.0.1", 8888,0.5);//调用connect将触发协程切换$client->send("hello world from swoole");//调用recv将触发协程切换$ret = $client->recv();$client->close();echo $ret;当代码执行到connect()和recv()函数时,swoole会触发进行协程切换,此时swoole可以去处理其他的事件或者接受新的请求。当此client连接成功或者后端服务回包后,swoole server会恢复协程上下文,代码逻辑继续从切换点开始恢复执行。开发者整个过程不需要关心整个切换过程。具体使用可以参考client的文档。注意事项全局变量:协程使得原有的异步逻辑同步化,但是在协程的切换是隐式发生的,所以在协程切换的前后不能保证全局变量以及static变量的一致性。请勿在以下场景中触发协程切换:析构函数魔术方法__call()gcc 4.4下如果在编译swoole的时候(即make阶段),出现gcc warning:dereferencing pointer ‘v.327’ does break strict-aliasing rules、dereferencing type-punned pointer will break strict-aliasing rules 请手动编辑Makefile,将CFLAGS = -Wall -pthread -g -O2替换为CFLAGS = -Wall -pthread -g -O2 -fno-strict-aliasing,然后重新编译make clean;make;make install与xdebug、xhprof等zend扩展不兼容,例如不能使用xhprof对协程server进行性能分析采样。在PHP5中,原生的call_user_func和call_user_func_array中无法使用协程client,请使用\Swoole\Coroutine::call_user_func和\Swoole\Coroutine::call_user_func_array代替在PHP7中可直接调用原生的call_user_func和call_user_func_array方法列表getDefer()bool getDefer();返回值:返回当前设置的defersetDefer()bool setDefer([bool $is_defer = true]);$is_defer:bool值,为true时,表明该Client要延迟收包,为false时,表明该Client非延迟收包,默认值为true返回值:设置成功返回true,否则返回false。只有一种情况会返回false,当设置defer(true)并发包后,尚未recv()收包,就设置defer(false),此时返回false。如果需要进行延迟收包,需要在发包之前调用recv()mixed recv();返回值:获取延迟收包的结果,当没有进行延迟收包或者收包超时,返回false。并发调用Client并发请求在协程版本的Client中,实现了多个客户端并发的发包功能。通常,如果一个业务请求中需要做一次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\ClientSwoole\Coroutine\RedisSwoole\Coroutine\MySQLSwoole\Coroutine\Http\Client除了Swoole\Coroutine\Client,其他Client都实现了defer特性,用于声明延迟收包。因为Swoole\Coroutine\Client的发包和收包方法是分开的,所以就不需要实现defer特性了,而其他Client的发包和收包都是在一个方法中,所以需要一个setDefer()方法声明延迟收包,然后通过recv()方法收包。协程版本Client并发请求示例代码:<?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

[1] [2]  下一页


Swoole Coroutine协程支持