今天給大家分享一個微軟官方的好東西:Channel,
?
前言
今天給大家分享一個微軟官方的生產者/消費者方案的特性解決:Channel,
Channel在System.Threading.Channels命名空間下,Core 2.1使用時,需要從Nuget上安裝,
% dotnet add package System.Threading.Channels
而在Core 3.0 preview 7開始,就直接包含在框架中了,
?
這是一個相對較新的特性,從Core 2.1開始加入,現在版本是5.0.0(嗯,這個版本號有點騙人,Channel的第一個版本就是4.5.0),
Channel能做什么?
邏輯上,Channel實際就是一個高效的、執行緒安全的佇列,支持在生產者和消費者之間傳遞資料,
利用Channel,通過發布和訂閱,可以將生產者和消費者分開,生產者Producer負責接收請求,并寫入Channel,而消費者Consumer為每個進入Channel的資料執行處理,這樣做,一方面可以使生產者和消費者并行作業來提高性能,另一方面,可以通過創建更多的生產者或消費者來提高應用的吞吐量,
為防止非授權轉發,這兒給出本文的原文鏈接:https://www.cnblogs.com/tiger-wang/p/14068973.html
下面,我們以一個實際例子,來解釋這個特性,
創建Channel
Channel提供了一個靜態Channel類,提供了兩個公開方法來創建兩種型別的Channel,
-
CreateUnbounded - 創建一個具有無限容量的Channel,
-
CreateBounded - 創建一個具有有限容量的Channel,
人通常來說,這兩種方式使用上沒有太大的區別,實際應用中,具體要看生產和消費的速度,以及期望產生的結果,有限容量的Channel,容量是有上限的,到達上限后,可以讓生產者非阻塞等待消費者使用并釋放Channel容量后再繼續,這種方式,好處是可以控制生產的速度,控制系統資源的使用,缺點也是,因為控制速度意味著生產速度會被限制,甚至停止,而無限容量,生產者可以全速進行生產,但也有缺點,如果消費者的消費速度低于生產者,Channel的資源使用會無限增加,會有服務器資源耗盡的可能,
?
今天的例子,我們使用無限Channel,
var channel = Channel.CreateUnbounded<string>();
非常簡單的一行代碼,就創建了一個無限容量的Channel,
我們定義這個Channel用來保存字串物件,
創建方法是一個通用的工廠方法,所以我們可以為需要使用的任何型別的物件和資料創建Channel,
?
Channel有兩個屬性:閱讀器回傳ChannelReader,寫入器回傳ChannelWriter,
寫入Channel
使用寫入器ChannelWriter,可以對Channel進行寫入操作,ChannelWriter提供了以下幾個方法:
- WriteAsync - 異步寫入
- WaitToWriteAsync - 非阻塞等待,直到有空間可寫入時或Channel關閉時,回傳true/false
- TryWrite - 嘗試寫入
- Complete - 標記Channel為關閉,并不再寫入資料到該Channel
- TryComplete - 嘗試標記Channel為關閉,
這幾個方法很容易理解,就不解釋了,
在本文的例子里,我用了:
await channel.Writer.WriteAsync("New message");
讀取Channel
使用閱讀器ChannelReader從Channel進行資料的讀取,也提供了幾個方法:
- ReadAsync - 異步讀取
- ReadAllAsync - 異步讀取Channel中的所有資料
- TryRead - 嘗試讀取
- WaitToReadAsync - 非阻塞等待,直到有資料可讀取或Channel關閉時,回傳true/false
不同的消費者模式,會用到不同的讀取方法,這個根據經驗來寫就好,
本文的例子中,我是采用WaitToReadAsync和ReadAsync配合來使用的:
while (await ChannelReader.WaitToReadAsync())
{
if (ChannelReader.TryRead(out var timeString))
{
/***/
}
}
WaitToReadAsync是一個非阻塞等待,在有訊息可讀或Channel關閉時,才會喚醒并繼續,
考慮到有多個消費者的情況,有可能別的執行緒已經進行了讀取,這兒使用TryRead進行讀取操作,
要注意:資料的同步作業是由Channel進行管理的,Channel會確保多個消費者不會讀到相同的資料,Channel同時也管理資料的次序,
示例代碼
今天的示例代碼我放到了Github上,鏈接是文章最后,
這個例子中,我做了三個場景,
首先是Channel,我使用了無限Channel,然后是創建生產者和消費者,資料傳輸程序就簡單化了,生產者只簡單將一個字串寫入到Channel,消費者也是,簡單等待并從Channel讀取資料字串,寫入控制臺,
三個場景分別是:
單一生產者/單一消費者
這個例子中,創建了一個生產者和一個消費者,兩者的任務都是并發啟動的,
里面的延時,是用來模擬作業負載的,
多個生產者/單一消費者
這個例子中有兩個生產者,通常在應用中有多個生產者時,我們需要確保生產與單個消費者所能處理的訊息數量大致相當,這樣能更好地利用服務器資源,
單一生產者/多個消費者
這個其實是應用中最常見的情況,就是產生訊息很快,但處理作業相關較慢,而且作業也更密集,這種情況,實際應用中我們可以通過擴大消費者數量來滿足生產的需求,
總結
最近的專案在做一個大資料的采集,用到了一些Channel的技術,然后發現網上這部分內容很少,就做了個例子,寫了這個文章,
Channel內容本身并不多,但用著很方便,而且實際應用中,比想像的更強大,它可以簡化很多生產者/消費者模式的使用,而且,任務間交換資料,使用Channel會更方便,更直接,
?
示例代碼在:https://github.com/humornif/Demo-Code/tree/master/0033/demo
![]() |
微信公眾號:老王Plus 掃描二維碼,關注個人公眾號,可以第一時間得到最新的個人文章和內容推送 本文著作權歸作者所有,轉載請保留此宣告和原文鏈接 |
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/228224.html
標籤:C#
下一篇:型別是什么

