天天看點

php為什麼需要異步程式設計?php異步程式設計的詳解(附示例)

本篇文章給大家帶來的内容是關于php為什麼需要異步程式設計?php異步程式設計的詳解(附示例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

我對 php 異步的知識還比較混亂,寫這篇是為了整理,可能有錯。

傳統的 php-fpm 一個程序執行一個請求,要達到多少并發,就要生成多少個程序。更糟糕的是每次請求都需要重新編譯執行,導緻并發一直上不來。是以出現了 Swoole 和 WorkerMan 兩個國内流行的常駐記憶體架構[1]。這兩個架構原理都是通過事件循環,讓程式一直停留在記憶體,等待外部請求,達到高并發。

為什麼需要異步

先來看一個例子

在工作目錄下建立檔案 slowServer.php

php為什麼需要異步程式設計?php異步程式設計的詳解(附示例)

開啟服務

php為什麼需要異步程式設計?php異步程式設計的詳解(附示例)

開另一個終端,安裝依賴

php為什麼需要異步程式設計?php異步程式設計的詳解(附示例)

建立檔案 worker.php

php為什麼需要異步程式設計?php異步程式設計的詳解(附示例)

開啟伺服器

php為什麼需要異步程式設計?php異步程式設計的詳解(附示例)

在浏覽器開啟兩個标簽,都打開網址

http://localhost:8082

。這時可以看到終端輸出“1”,過了一會兒又輸出“1”,原因是8081伺服器在處理第一個請求的時候阻塞在了等待8081傳回之中,等第一個請求結束後,才開始處理第二個請求。也就是說請求是一個一個執行的,要達到多少個并發,就要建立多少個程序,跟 php-fpm 一樣。現在修改一下代碼

php為什麼需要異步程式設計?php異步程式設計的詳解(附示例)

現在打開服務,再在浏覽器發起請求,發現第二個“1”在請求後就馬上輸出了,而這時第一個請求還沒結束。這表明程序不再阻塞,并發量取決于 cpu 和 記憶體,而不是程序數。

通過上面的例子已經很明白了,reactphp 架構通過把 http 請求變成異步,讓 onMessage 函數變成非阻塞,cpu 可以去處理下一個請求。即從 cpu 循環等待 8081 傳回,變成了 epoll 等待。

異步的意義在于把 cpu 從 io 等待中解放出來,可以處理其他計算任務。 如果你想知道怎麼用架構實作異步,看到這裡就可以了。WorkerMan 配合 ReactPHP 或者自身的 AsyncTcpConnection 已經可以滿足很多 io 請求異步化的需求。下面繼續讨論這些架構是怎麼做到異步的。

哪些地方應該被做成異步

通過上面的例子已經知道一旦執行到不需要 cpu,但是要等待 io 的時候,應該把 io 的過程做成異步。

實作事件循環

上面的例子是通過 reactphp 把 http 請求變成了異步,其實 WorkerMan 架構本身也是異步的,下面來看看 WorkerMan 是怎麼使 onMessage 函數可以異步接受請求。先來建立下面這個檔案 react.php

php為什麼需要異步程式設計?php異步程式設計的詳解(附示例)

開始執行

php為什麼需要異步程式設計?php異步程式設計的詳解(附示例)

在另一個終端執行

php為什麼需要異步程式設計?php異步程式設計的詳解(附示例)

這時就會看到第一個終端輸出'1'。

我之前寫過一篇文章《php使用epoll》,是這篇文章的基礎。那篇文章裡事件回調是通過定時來實作,即

php為什麼需要異步程式設計?php異步程式設計的詳解(附示例)

而這裡,事件回調是通過檢測 fd 是否有寫入内容來實作,這個過程不需要 cpu 參與。當 fd 有内容寫入時,會調函數 'react',這時開始使用 cpu。如果這時候程序執行另一個異步請求,比如用 reactphp 架構請求一個網頁,那麼程式會讓出 cpu,此時如果有另一個請求進來,就可以回調執行另一個 'react' 函數。由此提高了并發量。

協程

生成器 Generater

這是生成器的 PHP 官方文檔

http://php.net/manual/zh/lang...
php為什麼需要異步程式設計?php異步程式設計的詳解(附示例)

生成器就是每次程式執行到 yield 的時候儲存狀态,然後傳回 $i,是否繼續執行 gen_one_to_three 裡的循環,取決于主程式是否繼續調用

什麼是協程

上面的程式另一種寫法是

php為什麼需要異步程式設計?php異步程式設計的詳解(附示例)

由此可見,協程就是一種對函數的封裝,使其變成一種可以被中斷的函數,行為更像是子程序或子線程,而不是函數。協程的具體寫法這裡不細寫,因為協程的寫法十分複雜,可能需要再做一層封裝才能好用。

協程與異步

既然協程可以被中斷,那麼隻要在程式發起請求後發起事件循環,然後用 yield 傳回,然後程式繼續執行主程式部分,等事件傳回後觸發函數,執行 Generatot::next() 或 Generator::send() 來繼續執行協程部分。封裝好後就好像沒有異步回調函數一樣,和同步函數很像。

現在已經有 ampphp 和 swoole 兩個架構封裝了協程,有興趣可以了解一下。

以上就是php為什麼需要異步程式設計?php異步程式設計的詳解(附示例)的詳細内容,大型PHP項目實戰直播加入

link

免費擷取學習資料。