[TOC]
# 进程阻塞
******
正在运行的进程由于提出系统服务请求(如 I/O 操作),但因为某种原因未得到操作系统的立即响应,或者需要从其他合作进程获得的数据尚未达到等原因,该进程只能调用阻塞原语把自己阻塞,等待相应的事件出现后才被唤醒。
<br />
## 阻塞状态
正在进行的进程由于发生某事件而暂时无法继续执行时,便放弃处理继而处于暂停状态,亦即进程的执行收到阻塞,我们把这种暂停状态叫阻塞进程阻塞,有时也成为等待状态或封锁状态。通常这种处于阻塞状态的进程也排成一个队列。有的系统则根据阻塞原因的不同而处于阻塞状态的进程排成多个队列。
例如:
用户访问服务端,请求用户的个人的订单信息,由于数据库数据量大,数据库繁忙,sql 语句查询了 3 秒才返回,这个查询数据库的过程,就是可称为是“阻塞的”。(进程调用外部逻辑)
<br />
> 阻塞这个概念和时间关系不大,就算查了0.1秒,也可以说是阻塞了0.1秒,因为这个并不是进程本身执行所消耗的时间,而是因为查询数据库,等待数据库响应消耗的时间。但阻塞的危害性和时间有关,阻塞 0.1 秒对于用户是没有任何问题的,但是阻塞10秒将会使用户体验下降很多,所以我们需要重视阻塞。
> 用户访问服务端,由于某个地方调用了死循环或多重循环浪费了许多时间,无法继续往下执行,这个状态也可称为阻塞。(非进程阻塞,可自行避免)
> 非进程阻塞在进程阻塞层面中,并不算是被阻塞了,因为它依旧在执行过程中的代码,没有等待清空。
<br />
## 阻塞函数
如上所说,调用数据库等外部逻辑,造成阻塞的函数就叫做阻塞函数。
<br />
## php 中的阻塞
在 php 初级开发者中,或许没有听过这个概念,阻塞往往是和“同步”概念一起存在的,例如查询数据库,获取文件数据,请求其他网站,等等,只要需要消耗非进程本身执行时间并需要进程等待(同步)的,都可以说是阻塞。
> 几乎所有的阻塞,都是与 I/O 有关。
> 阻塞一定是同步代码调用阻塞函数才会阻塞,但同步代码不一定会阻塞(不调用阻塞函数的同步代码)
> ```php
> $num = 30;
> $result = M('test')->select(); // 伪代码,sql阻塞
> sleep(3); // 伪代码,当成执行了3秒才返回
> echo json_encode($result); // 返回数据
> ```
可自行搜索了解更多。
<br />
## 非阻塞
非阻塞,顾名思义,就是在进程在运行中,不存在阻塞情况,一直能往下执行。
> 非阻塞一般是指调用 I/O 操作时,进程无需等待 I/O 操作,直接往下执行的情况,非阻塞通常是和“异步”概念一起存在,只要是异步获取 I/O,就一定是非阻塞。
> 异步调用 I/O 一定是非阻塞的,但非阻塞不一定需要异步调用才可实现(非阻塞型)
例如:当查询数据库时,马上返回状态(查询到了就返回数据,数据还没到就返回 -1),程序可以立即往下执行逻辑。
> 这种马上返回结果,无需等待(并不一定有数据)的函数,就叫做非阻塞函数,也可称为是“异步调用”。
<br />
## 非阻塞模型
可以通过非阻塞模型去实现非阻塞(主要针对于 server 服务端实现)。详细了解可查:[非阻塞模型](http://blog.huanghui.xyz/2019/12/24/Swoole/Swoole%E5%9F%BA%E7%A1%80/C%E8%AF%AD%E8%A8%80%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-tcp%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%AE%9E%E7%8E%B0/)
<br />
## php中的非阻塞
php 初级开发者中,很少有非阻塞这个概念存在,但 php 是有非阻塞的,例如 socket\_set\_nonblock() 函数,将 socket 改为非阻塞状态。
通过 flock($file, LOCK\_EX|LOCK\_NB) 可将文件操作设置为非阻塞状态。
可自行搜索了解详细。
<br />
## 非阻塞注意事项
由于非阻塞的返回结果是不确定的,当我们需要关心返回结果的情况时,需要确保返回结果是正确的(例如 while(1) {} 定时查询,当数据正确返回退出循环),或者直接使用阻塞函数。
<br />
## 阻塞和非阻塞的举例
阻塞:
小明去电脑店买 Mac,问店员现在有没有 MacBook Pro 版本,有多少台,店员告诉小明,“我得去查一查,你得等等”,小明站在店门口等了2天,店员回来了,告诉小明,现在有 10 台,然后小明买了一台。
> 在这个过程中,店员查询是否有 mbp 的动作,就属于 I/O 操作,叫小明等等这个操作,就是阻塞情况,小明等了2天,就说明查询 mbp 时间为2天,阻塞了2天,店员回来告诉小明有10台,就是阻塞函数出现了结果,并返回了数据,小明买了一台,就是继续往下执行了代码。
非阻塞:
小明去电脑店买 Mac,问店员现在有没有 MacBook Pro 版本,有多少台,店员告诉小明,“我得去查一查,你先回去呗”,小明回家,每隔10分钟打电话给店员,但是店员每次都告诉他没查到,小明每次打完电话就去敲 PHP 代码,2天后,小明打完一把 LOL,又打电话给店员问,店员告诉小明,现在有10台了,然后小明买了一台。
> 在这个过程中,店员查询是否有 mbp 的动作,就属于 I/O 操作,叫小明回家这个操作,就是非阻塞情况,小明不断打电话,这个就是定时轮询查询,店员不断的回复,这个情况就是非阻塞函数没有返回数据,小明去敲 PHP,说明非阻塞情况还能执行其他代码,2天后,店员回来告诉小明有10台,就是非阻塞函数通过轮询出现了结果,并返回了数据,小明买了一台,就是退出了循环继续往下执行代码。
![](https://img.kancloud.cn/ef/9c/ef9c829f89b3a76b85a2efd62952c0c6_783x863.png)
- 引言
- Introduction
- 运行模式
- php-fpm
- php-cli
- 基础介绍
- 网络协议
- ip
- tcp
- tcp
- http
- webSocket
- udp
- port端口
- 会话管理
- cookie
- session
- api/token
- linux基础
- lnmp安装
- 命令
- 进程管理
- 扩展安装
- 端口监控
- 防火墙说明
- php7.0
- 部分新特性
- php回调/闭包
- 回调事件
- 闭包/匿名函数
- php多进程
- 多进程开启
- 进程通信
- 进程信号
- 僵尸进程
- 孤儿进程
- 守护进程
- 同步/异步
- 阻塞/非阻塞
- 协程
- Swoole
- 初始Swoole
- 运行机制
- 生命周期
- composer使用
- EasySwoole
- 设计理念
- 组件说明
- 运行过程
- demo
- 提问的艺术