生產者/消費者模式的理解及實現

来源:https://www.cnblogs.com/ruanshuxin/archive/2019/09/03/11455969.html
-Advertisement-
Play Games

★簡介 生產者消費者模式並不是GOF提出的23種設計模式之一,23種設計模式都是建立在面向對象的基礎之上的,但其實面向過程的編程中也有很多高效的編程模式,生產者消費者模式便是其中之一,它是我們編程過程中最常用的一種設計模式。 在實際的軟體開發過程中,經常會碰到如下場景:某個模塊負責產生數據,這些數據 ...


★簡介

生產者消費者模式並不是GOF提出的23種設計模式之一,23種設計模式都是建立在面向對象的基礎之上的,但其實面向過程的編程中也有很多高效的編程模式,生產者消費者模式便是其中之一,它是我們編程過程中最常用的一種設計模式。

在實際的軟體開發過程中,經常會碰到如下場景:某個模塊負責產生數據,這些數據由另一個模塊來負責處理(此處的模塊是廣義的,可以是類、函數、線程、進程等)。產生數據的模塊,就形象地稱為生產者;而處理數據的模塊,就稱為消費者。

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

img

​ 1、你把信寫好——相當於生產者製造數據

​ 2、你把信放入郵筒——相當於生產者把數據放入緩衝區

​ 3、郵遞員把信從郵筒取出——相當於消費者把數據取出緩衝區

​ 4、郵遞員把信拿去郵局做相應的處理——相當於消費者處理數據

★優點

可能有同學會問了:這個緩衝區有什麼用捏?為什麼不讓生產者直接調用消費者的某個函數,直接把數據傳遞過去?搞出這麼一個緩衝區作甚?

​ 其實這裡面是大有講究的,大概有如下一些好處。

◇解耦

​ 假設生產者和消費者分別是兩個類。如果讓生產者直接調用消費者的某個方法,那麼生產者對於消費者就會產生依賴(也就是耦合)。將來如果消費者的代碼發生變化,可能會影響到生產者。而如果兩者都依賴於某個緩衝區,兩者之間不直接依賴,耦合也就相應降低了。

​ 接著上述的例子,如果不使用郵筒(也就是緩衝區),你必須得把信直接交給郵遞員。有同學會說,直接給郵遞員不是挺簡單的嘛?其實不簡單,你必須得認識誰是郵遞員,才能把信給他(光憑身上穿的制服,萬一有人假冒,就慘了)。這就產生和你和郵遞員之間的依賴(相當於生產者和消費者的強耦合)。萬一哪天郵遞員換人了,你還要重新認識一下(相當於消費者變化導致修改生產者代碼)。而郵筒相對來說比較固定,你依賴它的成本就比較低(相當於和緩衝區之間的弱耦合)。

◇支持併發(concurrency)

​ 生產者直接調用消費者的某個方法,還有另一個弊端。由於函數調用是同步的(或者叫阻塞的),在消費者的方法沒有返回之前,生產者只好一直等在那邊。萬一消費者處理數據很慢,生產者就會白白糟蹋大好時光。

​ 使用了生產者/消費者模式之後,生產者和消費者可以是兩個獨立的併發主體(常見併發類型有進程和線程兩種,後面的帖子會講兩種併發類型下的應用)。生產者把製造出來的數據往緩衝區一丟,就可以再去生產下一個數據。基本上不用依賴消費者的處理速度。

​ 其實當初這個模式,主要就是用來處理併發問題的。

​ 從寄信的例子來看。如果沒有郵筒,你得拿著信傻站在路口等郵遞員過來收(相當於生產者阻塞);又或者郵遞員得挨家挨戶問,誰要寄信(相當於消費者輪詢)。不管是哪種方法,都挺土的。

◇支持忙閑不均

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

​ 為了充分復用,我們再拿寄信的例子來說事。假設郵遞員一次只能帶走1000封信。萬一某次碰上情人節(也可能是聖誕節)送賀卡,需要寄出去的信超過1000封,這時候郵筒這個緩衝區就派上用場了。郵遞員把來不及帶走的信暫存在郵筒中,等下次過來時再拿走。

​ 費了這麼多口水,希望原先不太瞭解生產者/消費者模式的同學能夠明白它是怎麼一回事。接下來說說數據單元。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Go語言中有個概念叫做goroutine, 這類似我們熟知的線程,但是更輕。 以下的程式,我們串列地去執行兩次loop函數: go package main import "fmt" func main() { loop() loop() } func loop() { for i := 0; i ...
  • 數組Array 1.數組的創建方式 字面量方式創建: 使用構造函數的方式創建(使用new關鍵字對構造函數進行創建對象) 2.數組的賦值 3.數組的常用方法 3.1 concat:把幾個數組合併成一個數組 3.2 join:將數組中的元素使用指定的字元串連接起來,他會形成一個新的字元串 3.3 將數組 ...
  • 來一道GIL面試題 描述python GIL的概念,以及他對python多線程的影響,編寫一個多線程抓取網頁的程式,並闡明多線程抓取程式是否比單線程有所提升,並解釋原因。 參考答案: 1.python語言和GIL沒有關係,僅僅是由於歷史原因在CPython虛擬機(解釋器),難以移除GIL 2.GIL ...
  • package com.atguigu;public class fuzhi { public static void main(String[] args) { int[] array1=new int[]{2,3,5,7,11,13,17,19};//靜態初始化 int[] array2; fo ...
  • 1.源文件聲明規則2.JAVA基本類型void3.數據類型預設值4.自動類型轉換5.Java變數類型6.Java局部變數7.訪問控制修飾符8.父類與子類的訪問控制9.instanceof運算符 1.源文件聲明規則 一個源文件中只能有一個public類 一個源文件中可以有多個非public類 源文件名 ...
  • 前言 ArrayList 作為 Java 集合框架中最常用的類,在一般情況下,用它存儲集合數據最適合不過。知其然知其所以然,為了能更好地認識和使用 ArrayList,本文將從下麵幾方面深入理解 ArrayList: 為什麼不用數組,用 ArrayList ArrayList 特性的源碼分析 Jav ...
  • 使用PHP 表單 表單處理: PHP超全局變數:$_GET 和 $ _POST 用於處理表單數據(form data) 表單標簽 ​ action屬性:規定表單數據提交URL ​ method屬性:規定提交時使用的HTTP方法(推薦POST) 表單元素標簽 ​ type屬性:動態定義標簽框的類型 H ...
  • 摘要: 事務在後端開發中無處不在,是數據一致性的最基本保證。要明白進事務的本質就是進到事務切麵的代理方法中,最常見的是同一個類的非事務方法調用一個加了事務註解的方法沒進入事務。我們以 代理為例,由於Spring的對於 代理的實現,進入被代理方法的時候實際上已經離開了“代理這一層殼子”,可以認為代碼走 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...