.NET 中 Channel 類簡單使用

来源:https://www.cnblogs.com/kklldog/p/18201013/channel-in-net
-Advertisement-
Play Games

Channel 是乾什麼的 The System.Threading.Channels namespace provides a set of synchronization data structures for passing data between producers and consume ...


Channel 是乾什麼的

The System.Threading.Channels namespace provides a set of synchronization data structures for passing data between producers and consumers asynchronously. The library targets .NET Standard and works on all .NET implementations.
Channels are an implementation of the producer/consumer conceptual programming model.
以上是微軟官方的解釋 channels。用中文說的話就是這個類提供了在生產者跟消費者之間非同步傳統數據的能力,簡單來說可以認為是一個記憶體消息隊列。

示例 1

下麵是一個簡單的示例,說明如何使用 Channel 類來創建一個生產者-消費者模型:

    static async Task Main(string[] args)
    {
        var channel = Channel.CreateUnbounded<int>();

        var producer = Task.Run(async () =>
        {
            for (int i = 0; i < 10; i++)
            {
                await channel.Writer.WriteAsync(i);
                await Task.Delay(1000); // 模擬生產者需要一些時間來生成數據
            }

            channel.Writer.Complete();
        });

        var consumer = Task.Run(async () =>
        {
            await foreach (var item in channel.Reader.ReadAllAsync())
            {
                Console.WriteLine($"消費者接收到: {item}");
            }
        });

        await Task.WhenAll(producer, consumer);
    }

在這個例子中,我們創建了一個無界的通道,然後創建了兩個任務,一個是生產者,一個是消費者。生產者每秒生成一個數字,然後寫入通道。消費者從通道中讀取數據並列印出來。當生產者完成寫入後,它會調用 channel.Writer.Complete() 來通知消費者沒有更多的數據可以讀取。

示例 2

你可以使用 Channel.CreateBounded(capacity) 方法來創建一個有界的通道,其中 capacity 參數指定了通道的容量。當通道滿時,嘗試寫入的操作將會阻塞,直到有空間可用。

    static async Task Main(string[] args)
    {
        var channel = Channel.CreateBounded<int>(5); // 創建一個容量為5的有界通道

        var producer = Task.Run(async () =>
        {
            for (int i = 0; i < 10; i++)
            {
                await channel.Writer.WriteAsync(i);
                Console.WriteLine($"生產者生成了: {i}");
                await Task.Delay(1000); // 模擬生產者需要一些時間來生成數據
            }

            channel.Writer.Complete();
        });

        var consumer = Task.Run(async () =>
        {
            await foreach (var item in channel.Reader.ReadAllAsync())
            {
                Console.WriteLine($"消費者接收到: {item}");
                await Task.Delay(2000); // 模擬消費者需要一些時間來處理數據
            }
        });

        await Task.WhenAll(producer, consumer);
    }

在這個例子中,我們創建了一個容量為5的有界通道。生產者每秒生成一個數字,然後寫入通道。消費者從通道中讀取數據並列印出來,但消費者處理數據的速度比生產者慢,所以當通道滿時,生產者的 WriteAsync 操作將會阻塞,直到消費者讀取了一些數據,使得通道有空間可用。

示例 3

下麵是一個示例,展示瞭如何在多個生產者和消費者之間共用一個通道:

    static async Task Main(string[] args)
    {
        var channel = Channel.CreateUnbounded<int>();

        // 創建兩個生產者
        var producer1 = Produce(channel.Writer, id: 1);
        var producer2 = Produce(channel.Writer, id: 2);

        // 創建兩個消費者
        var consumer1 = Consume(channel.Reader, id: 1);
        var consumer2 = Consume(channel.Reader, id: 2);

        // 等待所有生產者和消費者完成
        await Task.WhenAll(producer1, producer2, consumer1, consumer2);
    }

    static async Task Produce(ChannelWriter<int> writer, int id)
    {
        for (int i = 0; i < 10; i++)
        {
            await writer.WriteAsync(i);
            Console.WriteLine($"生產者{id}生成了: {i}");
            await Task.Delay(1000); // 模擬生產者需要一些時間來生成數據
        }

        writer.Complete();
    }

    static async Task Consume(ChannelReader<int> reader, int id)
    {
        await foreach (var item in reader.ReadAllAsync())
        {
            Console.WriteLine($"消費者{id}接收到: {item}");
            await Task.Delay(2000); // 模擬消費者需要一些時間來處理數據
        }
    }

在這個例子中,我們創建了兩個生產者和兩個消費者,它們都共用同一個通道。這是一個非常重要使用模式。因為當我們使用消息隊列的時候往往會有多個生產者跟多個消費者。我們可以通過控制生產者生產的速度來控制推入隊列的數據量。我們還可以通過控制消費者的數量來控制消費數據的速度,從而來調節系統的流量,達到消峰填谷的作用。

總結

Channel 類是 .NET CORE 3.0 後新加入的類。為我們提供了便利的生產者/消費者模式實現方案。相當於是一個進程內的記憶體隊列,而且它沒有持久化,純記憶體操作,性能是非常非常高的。當我們面對真正的高併發的時候可以為我們的系統提供吞吐量。當然代價是記憶體跟放棄一些實時性。

關註我的公眾號一起玩轉技術

QQ群:1022985150 VX:kklldog 一起探討學習.NET技術
作者:Agile.Zhou(kklldog)
出處:http://www.cnblogs.com/kklldog/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。


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

-Advertisement-
Play Games
更多相關文章
  • Polly 是一個在 C# 中用於處理瞬態故障和提供彈性的庫。它允許你以聲明式的方式定義策略,如重試、熔斷、超時、回退等,這些策略可以幫助你的代碼在出現故障時保持穩健和可靠。 以下是如何在 C# 中使用 Polly 實現重試策略的基本步驟: 首先,你需要在你的項目中安裝 Polly 包。這可以通過 ...
  • EasyBlog 說明 本博客系統通過構建工具生成純靜態的博客網站,藉助GitHub Pages,你可以在5分鐘內免費擁有個人博客。 它具有以下特點 生成純靜態網站,訪問速度極快 使用markdown格式來編寫博客內容 基於git代碼管理來存儲你的博客 使用CI工具來自動化部署你的博客站點 效果展示 ...
  • 開始做項目管理了(本人3年java,來到這邊之後真沒想到...),天天開會溝通整理需求,他們講話的時候忙裡偷閑整理一下常用的方法,其實語言還是有共通性的,基本上看到方法名就大概能猜出來用法。出去打水的時候看到外面太陽好好,真想在外面坐著曬太陽,回來的時候好兄弟三年前送給我的鍵盤D鍵不靈了,在打"等待 ...
  • 一:背景 1. 講故事 停了一個月沒有更新文章了,主要是忙於寫 C#內功修煉系列的PPT,現在基本上接近尾聲,可以回頭繼續更新這段時間分析dump的一些事故報告,有朋友微信上找到我,說他們的系統出現了大量的http超時,程式不響應處理了,讓我幫忙看下怎麼回事,dump也抓到了。 二:WinDbg分析 ...
  • 一、ReZero簡介 ReZero是一款.NET中間件 : 全網唯一開源界面操作就能生成API , 可以集成到任何.NET6+ API項目,無破壞性,也可讓非.NET用戶使用exe文件 免費開源:MIT最寬鬆協議 , 一直從事開源事業十年,一直堅持開源 1.1 純ReZero開發 適合.Net Co ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • 前言 Spacesniffer 是一個免費的文件掃描工具,通過使用樹狀圖可視化佈局,可以立即瞭解大文件夾的位置,幫助用戶處理找到這些文件夾 當前系統C盤空間 清理後系統C盤空間 下載 Spacesniffer 下載地址:https://spacesniffer.en.softonic.com/dow ...
  • efcore如何優雅的實現按年分庫按月分表 介紹 本文ShardinfCore版本 本期主角: ShardingCore 一款ef-core下高性能、輕量級針對分表分庫讀寫分離的解決方案,具有零依賴、零學習成本、零業務代碼入侵適配 距離上次發文.net相關的已經有很久了,期間一直在從事java相關的 ...
一周排行
    -Advertisement-
    Play Games
  • 下麵是一個標準的IDistributedCache用例: public class SomeService(IDistributedCache cache) { public async Task<SomeInformation> GetSomeInformationAsync (string na ...
  • 這個庫提供了在啟動期間實例化已註冊的單例,而不是在首次使用它時實例化。 單例通常在首次使用時創建,這可能會導致響應傳入請求的延遲高於平時。在註冊時創建實例有助於防止第一次Request請求的SLA 以往我們要在註冊的時候實例單例可能會這樣寫: //註冊: services.AddSingleton< ...
  • 最近公司的很多項目都要改單點登錄了,不過大部分都還沒敲定,目前立刻要做的就只有一個比較老的項目 先改一個試試手,主要目標就是最短最快實現功能 首先因為要保留原登錄方式,所以頁面上的改動就是在原來登錄頁面下加一個SSO登錄入口 用超鏈接寫的入口,頁面改造後如下圖: 其中超鏈接的 href="Staff ...
  • Like運算符很好用,特別是它所提供的其中*、?這兩種通配符,在Windows文件系統和各類項目中運用非常廣泛。 但Like運算符僅在VB中支持,在C#中,如何實現呢? 以下是關於LikeString的四種實現方式,其中第四種為Regex正則表達式實現,且在.NET Standard 2.0及以上平... ...
  • 一:背景 1. 講故事 前些天有位朋友找到我,說他們的程式記憶體會偶發性暴漲,自己分析了下是非托管記憶體問題,讓我幫忙看下怎麼回事?哈哈,看到這個dump我還是非常有興趣的,居然還有這種游戲幣自助機類型的程式,下次去大玩家看看他們出幣的機器後端是不是C#寫的?由於dump是linux上的程式,剛好win ...
  • 前言 大家好,我是老馬。很高興遇到你。 我們為 java 開發者實現了 java 版本的 nginx https://github.com/houbb/nginx4j 如果你想知道 servlet 如何處理的,可以參考我的另一個項目: 手寫從零實現簡易版 tomcat minicat 手寫 ngin ...
  • 上一次的介紹,主要圍繞如何統一去捕獲異常,以及為每一種異常添加自己的Mapper實現,並且我們知道,當在ExceptionMapper中返回非200的Response,不支持application/json的響應類型,而是寫死的text/plain類型。 Filter為二方包異常手動捕獲 參考:ht ...
  • 大家好,我是R哥。 今天分享一個爽飛了的面試輔導 case: 這個杭州兄弟空窗期 1 個月+,面試了 6 家公司 0 Offer,不知道問題出在哪,難道是杭州的 IT 崩盤了麽? 報名面試輔導後,經過一個多月的輔導打磨,現在成功入職某上市公司,漲薪 30%+,955 工作制,不咋加班,還不捲。 其他 ...
  • 引入依賴 <!--Freemarker wls--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.30</version> </dependency> ...
  • 你應如何運行程式 互動式命令模式 開始一個互動式會話 一般是在操作系統命令行下輸入python,且不帶任何參數 系統路徑 如果沒有設置系統的PATH環境變數來包括Python的安裝路徑,可能需要機器上Python可執行文件的完整路徑來代替python 運行的位置:代碼位置 不要輸入的內容:提示符和註 ...