一文读懂阻塞非阻塞 (非阻塞怎么实现)

简介: 当程序需要发送网络请求或者从磁盘中读取文件等IO操作时 CPU发出指令,然后信号经过总线到达网卡或者磁盘 然后拿到数据,再经过总线到达主存中,CPU继续对主存中的数据进行操作。

这篇文章,主要讲讲非堵塞编程带给程序的意义。 在我们谈到今天的主题之前,先来做一点基础知识的补充。

什么是I/O

非阻塞编程技术体系,非阻塞怎么实现

我们的计算机系统架构简易可看成如下,I/O接口连接其他硬件如:网卡、键盘鼠标、磁盘等。 I代表Input,输入数据。 O代表Output,输出数据。

当程序需要发送网络请求或者从磁盘中读取文件等IO操作时 CPU发出指令,然后信号经过总线到达网卡或者磁盘 然后拿到数据,再经过总线到达主存中,CPU继续对主存中的数据进行操作。

CPU的执行速率:主频 比如3GHz = 一秒钟有30亿个时钟脉冲,执行一条指令一般只需要几个时钟脉冲。也就是一秒可以执行的指令经常是以亿计算的。

以网络请求为例(磁盘IO也是一样的原理),当CPU发出指令之后,想要得到结果需要经过很长的等待(比如网络延迟经常是几十ms时间,CPU都过了多少千万个时钟脉冲了)

同步、异步、堵塞、非堵塞的概念

相信看这篇文章的你也不是第一次看到这种概念,在很多文章中经常会以购物等场景做例子。 这里只做一个简单的介绍: 同步、异步分为一组概念; 堵塞、非堵塞分为一组概念; (同步、异步):关注的是:数据的接收方式 (堵塞、非堵塞):关注的是:是否等待结果返回 这是两个分组(因为它们的关注点不同) 但是往往同步跟堵塞是一起的,异步跟非堵塞是一起的。 如果我们需要同步接收数据,肯定要让当前程序暂停,等待数据返回再做处理。

如果我们选择了异步接收数据,程序还堵塞的话那就没什么意义了,所以非堵塞模式,一般会返回发送调用请求的结果,然后程序继续执行,直到结果准备好了,再通过回调函数等方式触发程序做处理。

堵塞IO存在的不足

如果是堵塞IO的话,那么当前的进程会暂停执行,直到拿到数据才会继续执行。 文件锁堵塞 以PHP中自带的Session为例的文件锁 Session以生成文件储存的,如果同一个用户同时发起多个请求,先获取文件锁的请求可以执行,后面的拿不到文件锁,所以一直堵塞等待,假设前面的请求过了10s才执行完,后续的请求是要10s后才开始执行。 socket堵塞 写过tcp服务器的应该都会遇到这个问题 我们可以监听机器的某个端口,当有请求连接进来的时候,我们可以accept这个连接,然后读取客户端发过来的数据、发送数据回客户端等处理。

<?php
$socket = stream_socket_server("tcp://0.0.0.0:8000", $errno, $errstr);
if (!$socket) {
  echo "$errstr ($errno)<br />\n";
} else {
  // 循环接收客户端的连接
  while ($conn = stream_socket_accept($socket)) {
      $data = fread($conn, 8192); // 读取客户端发送过来的数据 读不到就一直堵塞着
      fwrite($conn, "hello world\n"); // 发送hello world
      fclose($conn);
  }
  fclose($socket);
}

以上代码实现了一个建议的TCP服务器,但是因为没有解决堵塞IO的问题,所以只能处理一个客户端的请求。

  • 当A连接进来,accept到,然后开始fread从缓冲区读取数据。 堵塞住了,进程执行暂停,等待数据结果。
  • 此时B连接进来,因为进程已经被堵塞住,所以无法被accept,更无法读取、发送数据。
  • A客户端发送了数据,进程恢复执行,开始读取,然后输出。
  • 然后才能accept B客户端(哪怕在此之前B已经发了很多数据,也只能从这个时候开始处理)。

非堵塞IO

为了让我们的网络服务器可以服务多个客户端,我们需要将程序改造为非堵塞的。 我们可以简单实现为:

  • 当A连接进来了,accept起来,存到一个列表中。
  • 继续等待监听,B连接进来了,accpet起来,存到一个列表中。
  • 多开一个线程,不断轮询连接列表,判断连接是否有发送数据过来,有的话就执行操作(比如发送数据、关闭连接)
  • 在PHP中默认没有线程操作,并且accept操作是堵塞的,但是可以设置超时时间

点击查看原文,获取更多福利!

https://developer.aliyun.com/article/1111156?utm_content=g_1000366196

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。