NIO、BIO、AIO 与 PHP 实现

前言

最近看到NIO,AIO,Netty,Promise话题很热,我作为一个phper也想来凑凑热闹,凑着凑着发现周围怎么都是javaer,jser。那么PHP能做NIOAIO么?

什么BIO、NIO、AIO

BIO 同步阻塞I/O。
有小伙伴又要问了啥叫 同步,啥叫阻塞啊?

同步/异步 阻塞/非阻塞

同步: 两个同步任务相互依赖,并且一个任务必须以依赖于另一任务的某种方式执行。 比如在A->B事件模型中,你需要先完成 A 才能执行B。 再换句话说,同步调用种被调用者未处理完请求之前,调用不返回,调用者会一直等待结果的返回。

异步: 两个异步的任务完全独立的,一方的执行不需要等待另外一方的执行。再换句话说,异步调用种一调用就返回结果不需要等待结果返回,当结果返回的时候通过回调函数或者其他方式拿着结果再做相关事情,

阻塞: 阻塞就是发起一个请求,调用者一直等待请求结果返回,也就是当前线程会被挂起,无法从事其他任务,只有当条件就绪才能继续。

非阻塞: 非阻塞就是发起一个请求,调用者不用一直等着结果返回,可以先去干其他事情。

以上就是这四个词汇的解释,那么放到计算机IO上,比较接地气的解释

BIO (Blocking I/O)

那么我们拿快递揽件来举例,一个快递公司,有一部分工作是揽件,它的工作模式是只能一个一个的揽件,你要寄快递,必须排队,一个一个的来,这就是 同步 。好不容易轮到你了,你把快递一扔给他,他还让给你等着,快递工作人员说,我们这后面还有些信息要录入,快递要检查,必须等我们快递公司检查完毕后,你才能离开,这叫 阻塞 。

NIO (No-Blocking I/O)

同步非阻塞的I/O

继续啊,拿快递公司举例。这个快递公司发现有些用户在后面排队,排着排着,太久了就去隔壁快递公司了,怎么办呢?快递公司想了个办法,置办了一个发号器和一批收纳盒。来一个客户,就把快递放在一个收纳盒里,再给用户一个编号,此时再来一个用户,不论前面一个的快递是否检查完毕,还是给他一个收纳盒,发一个编号。不同客户之间不排队,一来就被受理了,这就是 非阻塞。 我们再来看看内部,快递呢还是一个个地录入信息,X光检查,这样就是 同步 运行的,等待快递人员检查完毕叫号,客户拿到回执才能离开快递点。

AIO (Asynchronous I/O)

异步非阻塞IO

也有Javaer叫他 NIO2,快递公司揽件又升级了,做了一个快递柜,客户又寄件需求,来了就放入快递柜,然后通过手机扫码关注这个柜子的动态,客户就可以离开了,此时服务被受理,并能马上离开。这就是 非阻塞 。等到快递人员来揽件时,会将柜子里面的寄件一并取走,快递点集中一起处理这些快递件,发现有问题的件,不是立即停下手中的活等待客户来出来,而是放一旁通知客户来,然后继续处理下一个快递,这就是 异步

异步 阻塞 IO

同步/异步 阻塞/非阻塞,这4个名词,两两组和,还有一个就是 异步/阻塞

那么我们还是先把例子举出来吧,还是这个快递点,来了一批客户来寄口罩到国外,由于有很大的可能会通不过检查,所以,快递点把大家都留了下来。等所有的 寄件 都检查完了在统一给大家发送回执单,这就是 阻塞 。快递人员检查寄件时,发现问题不是立马通知客户来处理,而已放到一边,继续处理下一个。 这就是 异步

伪异步 IO

这种模式,底层实现是多个 同步阻塞的BIO, 同时运行。

最后总结一下:

阻塞与非阻塞指的的是当不能进行读写(网卡满时的写/网卡空的时候的读)的时候, I/ O操作立即返回还是阻塞;同步异步指的是,当数据已经 ready 的时候,读写操作是同步读还是异步读,阶段不同而已。

区别

异步/同步在计算机区别

以上是一些举例,只是帮助大家理解记忆,接下来我们看看计算上的实现。

最初计算机提供的Web服务,采用的是 CGI 协议,就是纯正的 BIO 模式。一个cgi进程监听一个端口,处理完一个请求,才能接收下一个http请求。这就是同步

而客户的实际体验式是”异步”的,那是因为后来优化了,CGI 程序能够自我fork进程的达到同时响应多个http请求的效果。

注意,我们这里讨论的基础是 单进程 ,上的 异步/同步

阻塞/非阻塞在计算机区别

这里拿购物流程举例,用户的下单,需要做如下操作:

  • 商品可售否
  • 库存数量
  • 用户余额
  • 触发哪些优惠规则
  • 奖券有效性

按照一般做法就是一步步验证,上一个检查完了,再进行下一个检查,这就是 阻塞 的方式。

那么非阻塞方式如何做呢,假设在微服务环境中,商品,库存,奖券,促销都是独立的系统,调用商品服务,发起商品可售检查请求;不等商品服务回复,继续调用库存服务,发起商品可售库存请求;紧接着依次发出…检查请求,这样5个检查项目的请求同时发起,最后,我等他们所有的请求都回复我,再来一起来校验是否所有的检查都通过了。就这种发起请求不等响应,就继续做下一件事的叫 非阻塞 。

PHP 能做什么

PHP 与 BIO 实现

PHP已经实现啦,这是最基本的好么。但平时测试时却感觉是不阻塞啊,好,我们来一起做个实验,将nginx和php-fpm的进程限制为1个试试。php-fpm就是 多进程的 BIO,现在我们强项改成单进程。

  • 调整Nginx配置

调整 /etc/nginx/nginx.conf 文件:

## 把nginx worker数量设置为1
worker_processes 1;

调整 /etc/php/php-fpm/conf.d/www.conf 文件:

pm = static
pm.max_children = 1
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 1

找到这几个配置都改为如上数值。