[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臺,就是非阻塞函數通過輪詢出現了結果,并返回了數據,小明買了一臺,就是退出了循環繼續往下執行代碼。

- 引言
- 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
- 提問的藝術