日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

架构设计:生产者/消费者模式 第3页:队列缓冲区

發布時間:2024/4/14 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 架构设计:生产者/消费者模式 第3页:队列缓冲区 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2019獨角獸企業重金招聘Python工程師標準>>>

[2]:隊列緩沖區

??? 經過前面兩個帖子的鋪墊,今天終于開始聊一些具體的編程技術了。由于不同的緩沖區類型、不同的并發場景對于具體的技術實現有較大的影響。為了深入淺出、便 于大伙兒理解,咱們先來介紹最傳統、最常見的方式。也就是單個生產者對應單個消費者,當中用隊列(FIFO)作緩沖。

??? 關于并發的場景,在之前的帖子“進程還線程?是一個問題!”中,已經專門論述了進程和線程各自的優缺點,兩者皆不可偏廢。所以,后面對各種緩沖區類型的介紹都會同時提及進程方式和線程方式。

??? ★線程方式

??? 先來說一下并發線程中使用隊列的例子,以及相關的優缺點。

??? ◇內存分配的性能

??? 在線程方式下,生產者和消費者各自是一個線程。生產者把數據寫入隊列頭(以下簡稱push),消費者從隊列尾部讀出數據(以下簡稱pop)。當隊列為空,消費者就稍息(稍事休息);當隊列滿(達到最大長度),生產者就稍息。整個流程并不復雜。

??? 那么,上述過程會有什么問題捏?一個主要的問題是關于內存分配的性能開銷。對于常見的隊列實現:在每次push時,可能涉及到堆內存的分配;在每次pop 時,可能涉及堆內存的釋放。假如生產者和消費者都很勤快,頻繁地push、pop,那內存分配的開銷就很可觀了。對于內存分配的開銷,用Java的同學可 以參見前幾天的帖子“Java性能優化[1]”;對于用C/C++的同學,想必對OS底層機制會更清楚,應該知道分配堆內存(new或malloc)會有 加鎖的開銷和用戶態/核心態切換的開銷。

??? 那該怎么辦捏?請聽下文分解,關于“生產者/消費者模式[3]:環形緩沖區”。

??? ◇同步和互斥的性能

??? 另外,由于兩個線程共用一個隊列,自然就會涉及到線程間諸如同步啊、互斥啊、死鎖啊等等勞心費神的事情。好在"操作系統"這門課程對此有詳細介紹,學過的 同學應該還有點印象吧?對于沒學過這門課的同學,也不必難過,網上相關的介紹挺多的(比如"這里"),大伙自己去瞅一瞅。關于這方面的細節,咱今天就不多 啰嗦了。

??? 這會兒要細談的是,同步和互斥的性能開銷。在很多場合中,諸如信號量、互斥量等玩意兒的使用也是有不小的開銷的(某些情況下,也可能導致用戶態/核心態切換)。如果像剛才所說,生產者和消費者都很勤快,那這些開銷也不容小覷啊。

??? 這又該咋辦捏?請聽下文的下文分解,關于“生產者/消費者模式[4]:雙緩沖區”。

??? ◇適用于隊列的場合

??? 剛才盡批判了隊列的缺點,難道隊列方式就一無是處?非也。由于隊列是很常見的數據結構,大部分編程語言都內置了隊列的支持(具體介紹見"這里"),有些語 言甚至提供了線程安全的隊列(比如JDK 1.5引入的ArrayBlockingQueue)。因此,開發人員可以撿現成,避免了重新發明輪子。

??? 所以,假如你的數據流量不是很大,采用隊列緩沖區的好處還是很明顯的:邏輯清晰、代碼簡單、維護方便。比較符合KISS原則。

??? ★進程方式

??? 說完了線程的方式,再來介紹基于進程的并發。

??? 跨進程的生產者/消費者模式,非常依賴于具體的進程間通訊(IPC)方式。而IPC的種類名目繁多,不便于挨個列舉(畢竟口水有限)。因此咱們挑選幾種跨平臺、且編程語言支持較多的IPC方式來說事兒。

??? ◇匿名管道

??? 感覺管道是最像隊列的IPC類型。生產者進程在管道的寫端放入數據;消費者進程在管道的讀端取出數據。整個的效果和線程中使用隊列非常類似,區別在于使用管道就無需操心線程安全、內存分配等瑣事(操作系統暗中都幫你搞定了)。

??? 管道又分命名管道和匿名管道兩種,今天主要聊匿名管道。因為命名管道在不同的操作系統下差異較大(比如Win32和POSIX,在命名管道的API接口和 功能實現上都有較大差異;有些平臺不支持命名管道,比如Windows CE)。除了操作系統的問題,對于有些編程語言(比如Java)來說,命名管道是無法使用的。所以我一般不推薦使用這玩意兒。

??? 其實匿名管道在不同平臺上的API接口,也是有差異的(比如Win32的CreatePipe和POSIX的pipe,用法就很不一樣)。但是我們可以僅 使用標準輸入和標準輸出(以下簡稱stdio)來進行數據的流入流出。然后利用shell的管道符把生產者進程和消費者進程關聯起來(沒聽說過這種手法的 同學,可以看"這里")。實際上,很多操作系統(尤其是POSIX風格的)自帶的命令都充分利用了這個特性來實現數據的傳輸(比如more、grep 等)。

??? 這么干有幾個好處:

??? 1、基本上所有操作系統都支持在shell方式下使用管道符。因此很容易實現跨平臺。

??? 2、大部分編程語言都能夠操作stdio,因此跨編程語言也就容易實現。

??? 3、剛才已經提到,管道方式省卻了線程安全方面的瑣事。有利于降低開發、調試成本。

??? 當然,這種方式也有自身的缺點:

??? 1、生產者進程和消費者進程必須得在同一臺主機上,無法跨機器通訊。這個缺點比較明顯。

??? 2、在一對一的情況下,這種方式挺合用。但如果要擴展到一對多或者多對一,那就有點棘手了。所以這種方式的擴展性要打個折扣。假如今后要考慮類似的擴展,這個缺點就比較明顯。

??? 3、由于管道是shell創建的,對于兩邊的進程不可見(程序看到的只是stdio)。在某些情況下,導致程序不便于對管道進行操縱(比如調整管道緩沖區尺寸)。這個缺點不太明顯。

??? 4、最后,這種方式只能單向傳數據。好在大多數情況下,消費者進程不需要傳數據給生產者進程。萬一你確實需要信息反饋(從消費者到生產者),那就費勁了。可能得考慮換種IPC方式。

轉載于:https://my.oschina.net/u/999937/blog/757124

總結

以上是生活随笔為你收集整理的架构设计:生产者/消费者模式 第3页:队列缓冲区的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。