十年河東,十年河西,莫欺少年窮
學無止境,精益求精
這裏需要聲明的是:
雖說 Channel 類似於 MQ ,但 Channel 並不支持跨項目使用,MQ 作爲中間件,它裏面的消息可以被多個項目共享,但 Channel 中的消息只能用於單體項目中共享。
介紹
首先,Channel本質上是.net中的一種新的集合類型,它與現有的Queue<T>
類型非常相似,當然也有不同之處。
System.Threading.Channels 是.NET Core 3.0 後推出的新的集合類型, 具有異步API,高性能,線程安全等特點,它可以用來做消息隊列,進行數據的生產和消費, 公開的 Writer
和 Reader
api對應消息的生產者和消費者,也讓Channel更加的簡潔和易用,與Rabbit MQ 等其他隊列不同的是,Channel 是進程內的隊列。
爲什麼要使用 Channels
可以利用 Channels 來實現 生產者和消費者
之間的解耦,大體上有兩個好處:
-
生產者 和 消費者 是相互獨立的,兩者可以並行執行。
-
如果生產者不給力,可以創建多個的生產者,如果消費者不給力,可以創建更多的消費者。
總的來說,在 生產者-消費者
模式下可以幫助我們提高應用程序的吞吐率。
創建Channel
nuget 中搜索 Channel 並安裝
channel 分爲固定容量的,和無限容量的
無限容量的Channel創建
//無限容量的 var channel_1 = Channel.CreateUnbounded<msgDto>(); var channel_2 = Channel.CreateUnbounded<string>(new UnboundedChannelOptions() { SingleWriter = false, //允許一次寫入多個消息 SingleReader = true //一次只能讀取一條消息 });
CreateUnbounded<T> 是指消息的類型,可以爲簡單的 int 、string 類型,也可以定義成一個類,上述的 msgDto 就是一個簡答的類
public class msgDto { public string msgid { get; set; } public string msg { get; set; } }
有限容量的Channel創建
//限容Channel var channel_3 = Channel.CreateBounded<string>(10000); var channel_4 = Channel.CreateBounded<msgDto>(new BoundedChannelOptions(100) { FullMode = BoundedChannelFullMode.Wait, //消息滿了 等待消費 新的消息不插入 SingleWriter = false,//允許一次寫入多條數據 SingleReader = false,//允許一次讀取多條數據 });
注意,BoundedChannelFullMode 共有四種
-
Wait 等待空間可用以便完成寫入操作。
-
DropWrite 刪除要寫入的項。
-
DropNewest 刪除並忽略通道中的最新項,以便爲要寫入的項留出空間。
-
DropOldest 刪除並忽略通道中的最舊項,以便爲要寫入的項留出空間。
生產/消費數據
static async Task Main(string[] args) { //Channel 屬於線程安全的集合 var channel_1 = Channel.CreateUnbounded<string>(new UnboundedChannelOptions() { SingleWriter = false, //允許一次寫入多條數據,下面的Parallel.For屬於多線程寫入 SingleReader = false }); //多線程寫入 Parallel.For(0, 10, i => { channel_1.Writer.WriteAsync ("hello_" + i); }); //消費數據 while (await channel_1.Reader.WaitToReadAsync()) { if (channel_1.Reader.TryRead(out var message)) { Console.WriteLine(message); } } Console.Read(); }
WaitToReadAsync是一個非阻塞等待,在有消息可讀或Channel關閉時,纔會喚醒並繼續。
考慮到有多個消費者的情況,有可能別的線程已經進行了讀取,這兒使用TryRead進行讀取操作。
要注意:數據的同步工作是由Channel進行管理的。Channel會確保多個消費者不會讀到相同的數據。Channel同時也管理數據的次序。
上述例子的輸出結果:
因爲是異步多線程寫入,因此,不保證順序,但讀取時,還是按照寫入的順序進行讀取的。
@天才臥龍的波爾卡