当前位置: 首页 > 后端技术 > PHP

PHP yield 高级用法——同步编码,异步执行

时间:2023-03-30 00:08:04 PHP

PHPyield的高级用法——同步编码,异步执行很多文章都在讲Iterator,Generator,clam~,这个东西是对PHPiterator的补充。再翻几页,就是Go协程。出于好奇,打开看了看Go协程,满满的都是并发,线程,管道通信,wc,nb,这tm是个黑科技,再看看PHP,想转行去每一分钟。你可以通过这篇文章,你可以学习如何编写一个简单的socket服务器,PHPyield的综合应用,Workerman的协程版本。四重yield语法探索yieldfrom语法探索yield实战“多线程”编码PHPyield高级用法网-PHPyield语法的最后一章yield语法是PHP5.5版本新增的,与迭代器一起使用,功能上是流控代码,类似转到并返回。下面是官方提供的yield的一个小例子。通过执行结果,我们可以分析出当代码执行到yield$i时,会返回$i。在echo"$value\n"之后,gotofor($i=1;$i<=3;$i++){,是的!PHP的yield是一个可以出去也可以进去的语法,在z代码里七进七出,$i就安全发出去了。count=1;$worker->onConnect=function(CoTcpConnection$connection){try{$conName="{$connection->getRemoteIp()}:{$connection->getRemotePort()}";回声PHP_EOL。“新连接,{$conName}\n”;$re=从$connection->readAsync(1024)产生;CoWorker::safeEch??o('获取请求消息:'。$re。PHP_EOL);从CoTimer::sleepAsync(1000*2)产生;$connection->send(json_encode(array('productId'=>12,'re'=>true)));CoWorker::safeEch??o('回应:'.$conName.PHP_EOL.PHP_EOL);}catch(ConnectionCloseException$e){CoWorker::safeEch??o('连接关闭,'.$e->getMessage().PHP_EOL);}};CoWorker::runAll();这里设置fork一个worker线程,处理逻辑中有一个sleep()2s的操作,仍然不影响同时响应多个请求启动测试程序##启动CoWorker服务$php./examples/example2/coWorkermanServer.phpstart##启动请求线程$php./examples/example2/userClientFork.php运行结果绿色箭头-newRequests,红色箭头-responserequests从结果我们可以看到,这个工作线程在接收新请求的同时,还在回复之前的请求,每个连接都是交错运行的。至于我们的代码,好像是同步的,没有回调。CoWorker购物车服务不错。这里我们做几个简单的微服务来模拟实际的应用。这里我们模拟了用户请求端、购物车服务、库存服务、商品服务。模拟用户请求添加购买,购物车单独请求库存,商品检测用户是否可以添加购买,响应客户请求是否成功。代码我就不贴了,太长了,请移步CoWorkerman/example/example5/coCartServer.phpruncommand##startinventoryservice$php./examples/example5/otherServerFork.php8081inventory1##startproductservice$php./examples/example5/otherServerFork.php8082product2##启动CoWorker购物车服务$php./examples/example5/coCartServer.phpstart##用户请求结束$php./examples/example5/userClientFork.phpRunningresult黄色箭头——新用户请求,蓝色箭头——购物车发起库存,商品验货请求,红色箭头——响应用户请求。从图中可以看出,一个线程同时为多个连接服务,交错运行。好吧,那PHPCoWorkerman也可以像NodeJS一样用Async/Await同步编码,异步运行。来试试这个CoWorkerman:$composerrequirepaulxu-cn/co-workerman工作原理首先上图:上图是Workerman的工作通道图,下图是Workerman的工作通道图同事。workerman中的worker进程遇到阻塞函数的处理方法,就会等待IO返回。如果此时有新的请求,空闲的worker就会去竞争这个新的连接。在上面的worker5中,我描述了AsyncTCPConnection的用法。在woker中发起了一个非阻塞请求,并注册了一个回调函数,然后程序一直运行到结束。当异步请求响应时,需要用其他方式响应(比如再发起一个请求通知请求者)。下图中,CoWorkerman也有多个worker竞争新的请求。当worker1收到新的请求时,会生成一个generator,在generator中发起一个异步请求,并注册一个response回调。请求响应后,会回到生成器跳出(yield)的地方,继续执行代码。发起异步请求并注册回调函数。这些默认任务已在CoWorkerman框架中完成。回调函数中的工作是:接收数据,发送给发起请求的生成器。本例通过调用Promise:all()发起多个请求,并返回结果。返回所有响应后,生成器继续运行。程序yield跳出后,worker处于事件循环状态($event->loop()),即多路监听:请求端口,第三方客户端请求响应端口。这时候如果有新的请求,就会和其他worker竞争新的请求。如果竞争达成,就会在worker中生成一个新的generator。如果客户端有响应,则调用回调函数,客户端有响应,继续运行生成器程序。从1我们可以假设,如果只有一个Worker,那么Worker可以在上一个请求没有完成的情况下,继续接受并处理下一个请求。即CoWorkerman可以在单个Worker下运行,并发处理多个请求。当然,这里也有一个前提。阻塞函数不能在单Worker模式下运行。一旦被阻塞,后续请求将被阻塞在网卡中。因此,除非你非常了解自己的代码,否则如果你使用了第三方库,那么我还是建议你在多Worker模式下运行CoWorkerman。阻塞时,有其他Worker去抓新的请求。CoWorkerman的意思是用同步代码发起异步请求,多个请求可以并发,从IO串行等待到并行等待,减少无畏等待的时间。在不降低代码可读性的情况下提高业务程序的效率。通过一个线程中的事件循环,处理尽可能多的请求,缓解一个请求一个线程带来的频繁线程切换,从核心提升运行效率。CoWorkerman生态小众适用于处理纯Socket请求的应用,比如WorkermanGateway,或者大前端集成多个服务RPC结果,合成后返回前三页的场景。日志记录是每个程序最基本的需求,因为写文件功能是阻塞的。推荐使用消息队列,或者redis队列,或者跳过Logstash直接扔Elasticsearch。CoWorkerman有其局限性,也有自己的立场。总结~PHP协程编码转网络异步编码到此结束。如果您看完本文有很多疑问,欢迎留言提问。如果不记得yield语法,可以看本系列前面几篇文章复习一遍。如果可以,请三连。谢谢同事!参考https://ericfu.me/several-way...https://segmentfault.com/a/11...