swoole教學介紹相關協程的面試問題
推薦(免費):swoole教學
什麼是進程?
流程就是應用程式的啟動實例。獨立的檔案資源,資料資源,記憶體空間。
什麼是執行緒?
執行緒屬於進程,是程式的執行者。一個行程至少包含一個主線程,也可以有更多的子執行緒。執行緒有兩種調度策略,一是:分時調度,二是:搶佔式調度。
我的官方企鵝群
什麼是協程?
協程是輕量級線程,協程也是屬於線程,協程是在線程裡執行的。協程的調度是使用者手動切換的,所以又叫用戶空間線程。協程的創建、切換、掛起、銷毀全部為記憶體操作,消耗量是非常低的。協程的調度策略是:協作式調度。
Swoole 協程的原理
Swoole4 由於是單執行緒多進程的,同一時間同一個行程只會有一個協程在執行。
Swoole server 接收資料在 worker 程序觸發 onReceive 回調,產生一個攜程。 Swoole 為每個請求建立對應攜程。協程中也能創造子協程。
協程在底層實作上是單執行緒的,因此同一時間只有一個協程在工作,協程的執行是串列的。
因此多任務多協程執行時,一個協程正在執行時,其他協程會停止工作。當前協程執行阻塞 IO 操作時會掛起,底層調度器會進入事件循環。當有 IO 完成事件時,底層調度器恢復事件對應的協程的執行。 。所以協程不存在 IO 耗時,非常適合高併發 IO 場景。 (如下圖)
Swoole 的協程執行流程
- ##協程沒有IO 等待正常執行PHP 程式碼,不會產生執行流程切換
- 協程遇到IO 等待立即將控制權切,待IO 完成後,重新將執行流切回原來協程切出的點
- 協程並行協程依序執行,同上一個邏輯
- 協程嵌套執行流程由外向內逐層進入,直到發生IO,然後切到外層協程,父協程不會等待子協程結束
go(function () { echo "hello go1 \n";});echo "hello main \n";go(function () { echo "hello go2 \n";});
go() 是
\Co::create() 的縮寫, 用來建立一個協程, 接受callback 作為參數, callback 中的程式碼, 會在這個新建的協程中執行.
\Swoole\Coroutine 可以簡寫為
\Co##上面的程式碼執行結果:
root@b98940b00a9b /v/w/c/p/swoole# php co.phphello go1 hello main hello go2
執行結果和我們平時寫程式碼的順序, 好像沒啥區別.實際執行過程:
- 運行此段程式碼, 系統啟動一個新行程
- 遇到
- go()
, 在目前行程中產生一個協程, 協程中輸出
heelo go1
, 協程退出 程式繼續向下執行程式碼, 輸出 - hello main
- heelo go2
, 協程退出
運行此段程式碼, 系統啟動一個新進程. 如果不理解這句話, 你可以使用如下程式碼:
// co.php<?phpsleep (100);
執行並使用
ps aux 查看系統中的進程:<pre class="brush:php;toolbar:false">root@b98940b00a9b /v/w/c/p/swoole# php co.php &⏎
root@b98940b00a9b /v/w/c/p/swoole# ps auxPID USER TIME COMMAND
1 root 0:00 php -a 10 root 0:00 sh 19 root 0:01 fish 749 root 0:00 php co.php 760 root 0:00 ps aux
⏎</pre>
我們來稍微改一改, 體驗協程的調度:
use Co;go(function () { Co::sleep(1); // 只新增了一行代码 echo "hello go1 \n";});echo "hello main \n";go(function () { echo "hello go2 \n";});#\Co::sleep()
函數函數和sleep()
差不多, 但是它模擬的是IO等待(IO後面會細講).執行的結果如下:<pre class="brush:php;toolbar:false">root@b98940b00a9b /v/w/c/p/swoole# php co.phphello main
hello go2
hello go1</pre>
怎麼不是順序執行的呢?實際執行程序:
- 遇到 go()
- ,在當前進程中產生一個協程
協程中遇到IO阻塞(這裡是
Co::sleep() - 模擬出的IO等待), 協程讓出控制, 進入協程調度佇列
進程繼續向下執行, 輸出
hello main -
執行下一個協程, 輸出
hello go2 -
#之前的協程準備就緒, 繼續執行, 輸出
hello go1
go(function () { Co::sleep(1); echo "hello go1 \n";});echo "hello main \n";go(function () { Co::sleep(1); echo "hello go2 \n";});
我想你已經知道輸出是什麼樣子了:
root@b98940b00a9b /v/w/c/p/swoole# php co.phphello main hello go1 hello go2 ⏎
协程快在哪? 减少IO阻塞导致的性能损失
大家可能听到使用协程的最多的理由, 可能就是 协程快. 那看起来和平时写得差不多的代码, 为什么就要快一些呢? 一个常见的理由是, 可以创建很多个协程来执行任务, 所以快. 这种说法是对的, 不过还停留在表面.
首先, 一般的计算机任务分为 2 种:
- CPU密集型, 比如加减乘除等科学计算
- IO 密集型, 比如网络请求, 文件读写等
其次, 高性能相关的 2 个概念:
- 并行: 同一个时刻, 同一个 CPU 只能执行同一个任务, 要同时执行多个任务, 就需要有多个 CPU 才行
- 并发: 由于 CPU 切换任务非常快, 快到人类可以感知的极限, 就会有很多任务 同时执行 的错觉
了解了这些, 我们再来看协程, 协程适合的是 IO 密集型 应用, 因为协程在 IO阻塞 时会自动调度, 减少IO阻塞导致的时间损失.
我们可以对比下面三段代码:
- 普通版: 执行 4 个任务
$n = 4;for ($i = 0; $i <pre class="brush:php;toolbar:false">root@b98940b00a9b /v/w/c/p/swoole# time php co.php1528965075.4608: hello 01528965076.461: hello 11528965077.4613: hello 21528965078.4616: hello 3hello main real 0m 4.02s user 0m 0.01s sys 0m 0.00s ⏎
- 单个协程版:
$n = 4;go(function () use ($n) { for ($i = 0; $i <pre class="brush:php;toolbar:false">root@b98940b00a9b /v/w/c/p/swoole# time php co.phphello main1528965150.4834: hello 01528965151.4846: hello 11528965152.4859: hello 21528965153.4872: hello 3real 0m 4.03s user 0m 0.00s sys 0m 0.02s ⏎
- 多协程版: 见证奇迹的时刻
$n = 4;for ($i = 0; $i <pre class="brush:php;toolbar:false">root@b98940b00a9b /v/w/c/p/swoole# time php co.phphello main1528965245.5491: hello 01528965245.5498: hello 31528965245.5502: hello 21528965245.5506: hello 1real 0m 1.02s user 0m 0.01s sys 0m 0.00s ⏎
为什么时间有这么大的差异呢:
普通写法, 会遇到 IO阻塞 导致的性能损失
单协程: 尽管 IO阻塞 引发了协程调度, 但当前只有一个协程, 调度之后还是执行当前协程
多协程: 真正发挥出了协程的优势, 遇到 IO阻塞 时发生调度, IO就绪时恢复运行
我们将多协程版稍微修改一下:
- 多协程版2: CPU密集型
$n = 4;for ($i = 0; $i <pre class="brush:php;toolbar:false">root@b98940b00a9b /v/w/c/p/swoole# time php co.php1528965743.4327: hello 01528965744.4331: hello 11528965745.4337: hello 21528965746.4342: hello 3hello main real 0m 4.02s user 0m 0.01s sys 0m 0.00s ⏎
只是将 Co::sleep()
改成了 sleep()
, 时间又和普通版差不多了. 因为:
sleep()
可以看做是 CPU密集型任务, 不会引起协程的调度Co::sleep()
模拟的是 IO密集型任务, 会引发协程的调度
这也是为什么, 协程适合 IO密集型 的应用.
再来一组对比的例子: 使用 redis
// 同步版, redis使用时会有 IO 阻塞$cnt = 2000;for ($i = 0; $i connect('redis'); $redis->auth('123'); $key = $redis->get('key');}// 单协程版: 只有一个协程, 并没有使用到协程调度减少 IO 阻塞go(function () use ($cnt) { for ($i = 0; $i connect('redis', 6379); $redis->auth('123'); $redis->get('key'); }});// 多协程版, 真正使用到协程调度带来的 IO 阻塞时的调度for ($i = 0; $i connect('redis', 6379); $redis->auth('123'); $redis->get('key'); });}
性能对比:
# 多协程版root@0124f915c976 /v/w/c/p/swoole# time php co.phpreal 0m 0.54s user 0m 0.04s sys 0m 0.23s ⏎# 同步版root@0124f915c976 /v/w/c/p/swoole# time php co.phpreal 0m 1.48s user 0m 0.17s sys 0m 0.57s ⏎
swoole 协程和 go 协程对比: 单进程 vs 多线程
接触过 go 协程的 coder, 初始接触 swoole 的协程会有点 懵, 比如对比下面的代码:
package main import ( "fmt" "time")func main() { go func() { fmt.Println("hello go") }() fmt.Println("hello main") time.Sleep(time.Second)}
> 14:11 src $ go run test.go hello main hello go
刚写 go 协程的 coder, 在写这个代码的时候会被告知不要忘了 time.Sleep(time.Second)
, 否则看不到输出 hello go
, 其次, hello go
与 hello main
的顺序也和 swoole 中的协程不一样.
原因就在于 swoole 和 go 中, 实现协程调度的模型不同.
上面 go 代码的执行过程:
- 运行 go 代码, 系统启动一个新进程
- 查找
package main
, 然后执行其中的func mian()
- 遇到协程, 交给协程调度器执行
- 继续向下执行, 输出
hello main
- 如果不添加
time.Sleep(time.Second)
, main 函数执行完, 程序结束, 进程退出, 导致调度中的协程也终止
go 中的协程, 使用的 MPG 模型:
- M 指的是 Machine, 一个M直接关联了一个内核线程
- P 指的是 processor, 代表了M所需的上下文环境, 也是处理用户级代码逻辑的处理器
- G 指的是 Goroutine, 其实本质上也是一种轻量级的线程
而 swoole 中的协程调度使用 单进程模型, 所有协程都是在当前进程中进行调度, 单进程的好处也很明显 – 简单 / 不用加锁 / 性能也高.
无论是 go 的 MPG模型, 还是 swoole 的 单进程模型, 都是对 CSP理论 的实现.
以上是當被swoole協程三連問時,快哭了!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本文概述了為Swoole項目做出貢獻的方法,包括報告錯誤,提交功能,編碼和改進文檔。它討論了初學者開始貢獻的必要技能和步驟,以及如何找到緊迫的是

本文討論了在PHP中使用Swoole的異步I/O功能用於高性能應用程序。它涵蓋安裝,服務器設置和優化策略。單詞計數:159

Swoole的反應堆模型使用事件驅動的,非阻滯I/O架構來有效地管理高持續性場景,通過各種技術優化性能。(159個字符)(159個字符)

摘要:本文討論了通過識別,隔離和固定解決SWOORE應用程序中的內存洩漏,並強調了常見原因,例如不當資源管理和不受管理的Coroutines。 Swoole Tracker和Valgrind等工具


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Atom編輯器mac版下載
最受歡迎的的開源編輯器

Dreamweaver CS6
視覺化網頁開發工具

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能