前言最近看到NIO、AIO、Netty、Promise的话题很火。作为一个phper,我也想凑个热闹,发现身边有javaer,jser。那么PHP可以做NIO、AIO吗?什么BIO、NIO、AIOBIO同步阻塞I/O。有朋友又要问什么是同步,什么是阻塞?Synchronous/AsynchronousBlocking/Non-blockingSynchronous:两个同步任务相互依赖,一个必须以某种依赖于另一个的方式执行。比如在A->B事件模型中,需要先完成A再执行B。换句话说,在同步调用的被调用者处理完请求之前,调用不会返回,调用者会一直等待要返回的结果。异步:两个异步任务完全独立,一个的执行不需要等待另一个的执行。也就是说,异步调用一调用就返回结果,不需要等待结果返回。当返回结果时,它使用回调函数或其他方法来保存结果,然后做相关的事情。阻塞:阻塞是发起一个请求,调用者一直在等待请求结果返回,即当前线程会被挂起,无法从事其他任务,只有条件具备了才能继续执行。非阻塞:非阻塞就是发起一个请求,调用者不必等待结果返回,可以先做其他事情。以上就是这四个字的解释,那就放到电脑IO上,更接地气的BIO(BlockingI/O)的解释,那我们就拿快递举例子,一个快递公司,一部分工作是收集包裹,其工作模式是只能一件一件地取件。如果要发快递,必须排队,一个一个来。这就是同步。终于轮到你了,你把快递扔给他,他让你等,快递员说,我们还有一些资料要录入,快递需要验货,必须等我们快递公司查完,只有你可以离开,这叫做阻塞。NIO(No-BlockingI/O)同步非阻塞I/O继续,以快递公司为例。快递公司发现有用户在他们身后排队。许久之后,他们才去了隔壁的快递公司。他们应该怎么办?快递公司想了个办法,买了一个发号器和一批收纳箱。当客户来时,将快递放在储物箱中并给用户一个编号。这时候又来了一个用户,不管之前的快递员有没有查过,还是给他一个储物箱和一个号码。不同客户之间无需排队,一来即受理。这是非阻塞的。我们再来看看内饰。快递员还是一一录入信息,进行X光检测。这是一个“同步”操作。等待快递员验货完毕并拨打号码,客户收到收货后方可离开快递点。AIO(AsynchronousI/O)异步非阻塞IO也被Javaer称为NIO2。快递公司对包裹进行了升级,做了快递柜。客户需要重新寄包裹。到了就放在快递柜里,然后用手机扫码关注这个柜子的动态,客户就可以走了。这时候接受了服务,他可以马上离开。这是非阻塞的。快递员上门取件时,会把柜子里的东西全部拿走。快递点会统一处理这些快递物品。在一旁通知客户,然后继续处理下一个快递,这是异步的。AsynchronousblockingIOsynchronous/asynchronousblocking/non-blocking,这4个名词,两组,一个是asynchronous/blocking。那么我们先举个例子,还是这个快递点,有一批客户来往国外寄口罩,因为有很大的可能会过不了检,所以快递点留着大家。所有“已发送物品”都核对完后,收据会统一发给大家,这就是“堵”。快递员查收时发现出现问题并没有立即通知客户处理,而是搁置一旁继续处理下一个。这是异步的。伪异步IO模式下,底层实现是多个同步阻塞的BIO同时运行。最后总结一下:阻塞和非阻塞是指当无法进行读写时(网卡满时写入/网卡空时读取),I/O操作立即返回或阻塞;同步和异步是指当数据准备好时,读写操作是同步还是异步,阶段不同。计算机中异步和同步的区别只是几个例子,只是为了帮助你理解内存。接下来,让我们看看计算中的实现。计算机提供的Web服务最初使用的是CGI协议,是一种纯BIO模型。一个cgi进程监听一个端口,处理完一个请求后才能接收下一个http请求。这就是同步。客户的实际体验是“异步”的,那是因为经过优化,CGI程序可以通过自fork进程同时响应多个http请求。请注意,我们在这里讨论的基础是单进程的异步/同步。阻塞/非阻塞是计算机之间的区别。这是购物过程的示例。用户下单时,需要做以下操作:商品是否可售、库存数量、用户余额、有哪些优惠规则、优惠券有效期……按照惯例,这是一步一步的验证。一次检查结束后,进行下一次检查。这是阻塞的方式。那么如何以非阻塞的方式做到这一点呢?假设在微服务环境下,商品、库存、优惠券、促销都是独立的系统,调用商品服务,发起请求查询商品是否有货;不等商品服务回复,继续调用库存服务。发起商品盘点请求;然后一个一个发送...检验请求,这样就同时发起了五个检验项目的请求。最后我会等他们所有的要求都回复我,然后一起来验证是否所有的检查都通过了。向上。发起一个请求,不等待响应,继续做下一件事,这叫做非阻塞。转载自名源sifouPHPPHP和BIO能实现什么PHP已经实现了,这个是最基本的。但是在正常测试的时候不会有堵车的感觉。好吧,我们一起来做个实验,尽量把nginx和php-fpm的进程限制为一个。php-fpm是多进程BIO,现在我们的实力改成单进程。调整Nginx配置,调整/etc/nginx/nginx.conf文件:##设置nginxworker数量为1worker_processes1;之后我们通过ps命令检查调整PHP配置,调整/etc/php/php-fpm/conf.d/www.conf文件:pm=staticpm.max_children=1pm.start_servers=1pm.min_spare_servers=1pm.max_spare_servers=1找到这些配置,改成上面的值。最终结果如下。我在index.php代码的第一行添加了睡眠。$client){while(true){//读取套接字数据$msg=@fread($client,1024);//$msg=1;if($msg){//应用进程}else{if(feof($client)){//TODO检查数据eof}break;}可以看出,在文件~/nio_server.php中,虽然设置了stream_set_blockingfalse,但是209行的fread()是循环读取的,属于阻塞读取。该系统函数的响应速度受系统IO的影响。在异步调用中,当有I/O事件发生时,系统会将数据拷贝到用户内存中,即准备数据,然后通知用户程序。那么原生PHP显然是不支持的,这里需要引入PHP扩展,也就是Event,或者Ev扩展。本篇博客主要讲Event。Event扩展是基于libevent库封装的,而Ev扩展是基于libev库封装的。你可以通过PHP接口和与C库的接口看到它们之间的联系。因此,如果通过PHP文档找不到相关信息,可以去看看C库的文档。而且Libevent年久失修,不推荐大家使用。下面是用Event实现的TcpServerdemo。在这个事件演示中,我使用了EventBuffer。读取和写入都与Buffer交互。缓冲区数据是用户态数据,不会等待系统I/O,也不会被阻塞。避免程序将时间花在I/O数据复制上。因此PHP也可以实现AIO程序来提高CPU利用率。说到这里,你会觉得这个PHPAIO有点牵强。找了其他博主的论据帮助大家理解。这两张图展示了用户程序和内核使用分块和异步交互的异同。上面是非阻塞IO,下面是异步IO。中间不同的是非阻塞IO的应用,需要不断访问内核获取数据(当然每次访问都是有响应的,都能获取到数据),但不一定能完成检索;异步IO的特点就是你告诉内核去取数据,等取完了,我再一起发给应用程序。这是Linux对异步IO的定义。然后再看看我们的demo。这是一个简单的TCP服务器。TCP请求系统可以知道数据包的大小以及是否已收到。这就是传输层需要做的事情。在应用层面,我们需要在接收到数据后,对数据进行合并、分包、转码。这意味着AIO数据的结果必须是完整的,而且概率有些不同(显然在系统层面是完整的)。在应用层面,一次接收到的数据可能不完整,所以需要额外的代码来解决关闭、分包和浸渍的问题。这是AIO实现TcpServer的需要。为了解决以上问题,需要自定义TCP通信协议。相当于自己开发RPC框架。那么我们再来看看Http。应用层面有清晰开放的协议(协议有头无尾,表示每次请求的具体长度),有丰富的实现。这是一个非常适合AIO编程的协议。PHP的Event扩展恰好是EventHttp实现的。话不多说,我们先上demo。getUri(),PHP_EOL;//打印请求的标题echo"Inputheaders:";var_dump($req->getInputHeaders());echo"\n>>正在发送回复...";/***@var\EventBuffer$buf*/$buf=$req->getOutputBuffer();$buf->add("这是关于事件http服务器");$req->sendReply(200,"OK",$buf);echo"OK\n";}这里是回调函数,入参是EventHttp封装的http请求对象。这就满足了上面的非阻塞调用,数据准备好后通知回调——异步I/O。好了,借助Event,PHP实现了AIO。结语关于性能提升,这里不做压力测试,主要论证PHP实现NIO和AIO的可行性。它还实际向您展示了几个Demo,这些Demo只是简单地展示了如何编写异步和非阻塞程序。可见异步编程对大家的要求还是比较高的。当需要发起IO操作时,必须以非阻塞的方式调用,否则整个进程都会阻塞,纯异步编程是单进程。阻塞后,服务无法响应新的请求。同时,我们经常会使用到PDO、mysqli、Redis等扩展,这些扩展只提供阻塞读接口。在现在的PHP环境下,可以说“几乎所有”的第三方框架都是阻塞代码。如果你在项目中使用了其他框架,那么你写的代码是没有问题的,不能保证你依赖的第三方框架会阻塞请求。输入\输出。所以一般的PHP异步编程都会采用多进程异步,让异步来提高每个请求的响应速度,如果进程阻塞了,让其他空闲的进程去处理新进来的请求。以上,希望大家通过文章了解异步/同步和阻塞/非阻塞的区别,以及PHP的异步和非阻塞编程。有问题欢迎提问~参考PHP实现非阻塞PHP复习socket编程Cooperativemultitaskingusingcoroutines(inPHP!)IO-synchronous,asynchronous,blocking,non-blockingsynchronous/asynchronous,blocking/non-阻塞概念深入剖析PHP高性能I/O框架:Libevent网络编程(三):从libevent到事件通知机制
