1. 程式人生 > >一看就懂系列之 php中的生產者and消費者模式

一看就懂系列之 php中的生產者and消費者模式

前言

在工作中常常聽到某某大牛之間的交談會涉及到,xx消費者啊啥的,到底什麼大牛之間講的是什麼?
這篇文章主要解決三個問題:
1.到底什麼是生產者和消費者,以及它們之間的故事
2.它們之間靠什麼交流
3.應用場景

正文

一、什麼是生產者和消費者,以及它們之間的故事

在實際的程式開發中,會經常碰到這樣的情況:小a模組負責生產資料,這些資料由另外一個模組負責處理。產生資料的模組,就形象地稱為生產者;而處理資料的模組,就稱為消費者。

單單抽象出生產者和消費者,還夠不上是生產者/消費者模式。該模式還需要有一個緩衝區處於生產者和消費者之間,作為一箇中介。生產者把資料放入緩衝區,而消費者從緩衝區取出資料。大概的結構如下圖。

這裡寫圖片描述

可以這麼理解,你(生產者)需要寫信寄給基友,你先放到郵箱(緩衝區),郵遞員(消費者)從郵箱取信進行派送(資料處理)。

那麼有同學問了,好好的生產者和消費者直接溝通不就好了,搞出一個緩衝區是做甚?
其實這是有內涵(優點)的:

解耦

假設生產者和消費者都是兩個類,如果直接讓生產者調消費者的類的方法,勢必會使其依賴於消費者的類方法,萬一消費者的消費方式改變(函式改掉啦)那麼生產者也要改。好了,程式碼耦合了。

那麼如果有了緩衝區就不一樣了,兩個都依賴於緩衝區,緩衝區只起到緩衝資料作用,一邊存一邊取,互不關聯也不依賴。

ps:你寫信直接交給郵遞員,萬一郵遞員換了,那你不是還要重新認識一下,還要關心是不是真的郵遞員。那如果是放郵箱的話,郵遞員是誰和你半毛錢關係沒有。

支援併發

生產者直接調消費者某個方法有個弊端:由於函式是同步的,也可以說是阻塞的,消費者沒返回之前,生產者只能一直等著,萬一消費者處理的又很慢,那生產者空閒著就浪費了。
使用了生產者/消費者模式之後,生產者和消費者可以是兩個獨立的併發主體。生產者把製造出來的資料往緩衝區一丟,就可以再去生產下一個資料。基本上不用依賴消費者的處理速度。

ps:如果沒郵箱,你就要站在等郵遞員來,想必這是坑爹的一件事。

支援生產消費者忙閒不均

緩衝區還有另一個好處。如果製造資料的速度時快時慢,緩衝區的好處就體現出來了。當資料製造快的時候,消費者來不及處理,未處理的資料可以暫時存在緩衝區中。等生產者的製造速度慢下來,消費者再慢慢處理掉。

ps:萬一今天是情人節啥的,寄信的人特別多,郵遞員一回只能帶100封,那麼多餘100封的部分就可以放在郵箱,等處理好100封后再回頭取,繼續處理。

它們之間靠什麼交流

那麼生產者和消費者之間怎麼交流呢?當然是通過資料單元交流的。何謂資料單元捏?簡單地說,每次生產者放到緩衝區的,就是一個數據單元;每次消費者從緩衝區取出的,也是一個數據單元。

ps:寄信,信就是資料單元

那麼資料單元涉及到一個很關鍵的問題,就是資料粒度的問題。
有時出於效能等因素的考慮,也可能會把N個業務物件打包成一個數據單元。那麼,這個N該如何取值就是顆粒度的考慮了。顆粒度的大小是有講究的。太大 的顆粒度可能會造成某種浪費;太小的顆粒度可能會造成效能問題。顆粒度的權衡要基於多方面的因素,以及一些經驗值的考量。

ps:還是拿寄信的例子。如果顆粒度過小(比如設定為1),那郵遞員每次只取出1封信。如果信件多了,那就得來回跑好多趟,浪費了時間。
如果顆粒度太大(比如設定為100),那寄信的人得等到湊滿100封信才拿去放入郵筒。假如平時很少寫信,就得等上很久,會很不爽滴~

應用場景

那麼在php中哪些地方會用到呢,或者說哪些地方會看到別人用到生產者和消費者模式?這裡簡單講幾個:

swoole

對,你沒看錯,就是swoole。那麼swoole其實是有使用了這個設計的模式,業務邏輯(生產者)將資料單元通過swoole的send函式弄到swoole的一個緩衝區之間,通過work程序進行分發,task程序(消費者)進行消費。

耗時操作的非同步處理

當“耗時操作“遇到了”高併發“,如果不採取一點措施,卡慢崩會慢慢到來,此時可以將要處理的耗時操作的相關資訊(資料單元)通過業務邏輯[生產者]push到redis佇列中(redis只是舉例),在通過跑一個指令碼的程序[消費者]進行pop出資料單元進行處理。