您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關await foreach怎么在C# 8.0中使用,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
static int SumFromOneToCount(int count) { ConsoleExt.WriteLine("SumFromOneToCount called!"); var sum = 0; for (var i = 0; i <= count; i++) { sum = sum + i; } return sum; }
調用方法.
static void Main(string[] args) { const int count = 5; ConsoleExt.WriteLine($"Starting the application with count: {count}!"); ConsoleExt.WriteLine("Classic sum starting."); ConsoleExt.WriteLine($"Classic sum result: {SumFromOneToCount(count)}"); ConsoleExt.WriteLine("Classic sum completed."); ConsoleExt.WriteLine("################################################"); }
輸出結果.
可以看到,整個過程就一個線程Id為1的線程自上而下執行,這是最基礎的做法.
Yield Return
接下來,我們使用yield運算符使得這個方法編程延遲加載,如下所示.
static IEnumerable<int> SumFromOneToCountYield(int count) { ConsoleExt.WriteLine("SumFromOneToCountYield called!"); var sum = 0; for (var i = 0; i <= count; i++) { sum = sum + i; yield return sum; } }
主函數
static void Main(string[] args) { const int count = 5; ConsoleExt.WriteLine("Sum with yield starting."); foreach (var i in SumFromOneToCountYield(count)) { ConsoleExt.WriteLine($"Yield sum: {i}"); } ConsoleExt.WriteLine("Sum with yield completed."); ConsoleExt.WriteLine("################################################"); ConsoleExt.WriteLine(Environment.NewLine); }
運行結果如下.
正如你在輸出窗口中看到的那樣,結果被分成幾個部分返回,而不是作為一個值返回。以上顯示的累積結果被稱為惰性枚舉。但是,仍然存在一個問題,即 sum 方法阻塞了代碼的執行。如果你查看線程ID,可以看到所有東西都在主線程1中運行,這顯然不完美,繼續改造.
Async Return
我們試著將async用于SumFromOneToCount方法(沒有yield關鍵字).
static async Task<int> SumFromOneToCountAsync(int count) { ConsoleExt.WriteLine("SumFromOneToCountAsync called!"); var result = await Task.Run(() => { var sum = 0; for (var i = 0; i <= count; i++) { sum = sum + i; } return sum; }); return result; }
主函數.
static async Task Main(string[] args) { const int count = 5; ConsoleExt.WriteLine("async example starting."); // Sum runs asynchronously! Not enough. We need sum to be async with lazy behavior. var result = await SumFromOneToCountAsync(count); ConsoleExt.WriteLine("async Result: " + result); ConsoleExt.WriteLine("async completed."); ConsoleExt.WriteLine("################################################"); ConsoleExt.WriteLine(Environment.NewLine); }
運行結果.
我們可以看到計算過程是在另一個線程中運行,但結果仍然是作為一個值返回!任然不完美.
如果我們想把惰性枚舉(yield return)與異步方法結合起來,即返回Task<IEnumerable,這怎么實現呢?
Task<IEnumerable>
我們根據假設把代碼改造一遍,使用Task<IEnumerable<T>>來進行計算.
可以看到,直接出現錯誤.
IAsyncEnumerable
其實,在C# 8.0中Task<IEnumerable>這種組合稱為IAsyncEnumerable。這個新功能為我們提供了一種很好的技術來解決拉異步延遲加載的問題,例如從網站下載數據或從文件或數據庫中讀取記錄,與 IEnumerable 和 IEnumerator 類似,Async Streams 提供了兩個新接口 IAsyncEnumerable 和 IAsyncEnumerator,定義如下:
public interface IAsyncEnumerable<out T> { IAsyncEnumerator<T> GetAsyncEnumerator(); } public interface IAsyncEnumerator<out T> : IAsyncDisposable { Task<bool> MoveNextAsync(); T Current { get; } } // Async Streams Feature 可以被異步銷毀 public interface IAsyncDisposable { Task DiskposeAsync(); }
AsyncStream
下面,我們就來見識一下AsyncStrema的威力,我們使用IAsyncEnumerable來對函數進行改造,如下.
static async Task ConsumeAsyncSumSeqeunc(IAsyncEnumerable<int> sequence) { ConsoleExt.WriteLineAsync("ConsumeAsyncSumSeqeunc Called"); await foreach (var value in sequence) { ConsoleExt.WriteLineAsync($"Consuming the value: {value}"); // simulate some delay! await Task.Delay(TimeSpan.FromSeconds(1)); }; } private static async IAsyncEnumerable<int> ProduceAsyncSumSeqeunc(int count) { ConsoleExt.WriteLineAsync("ProduceAsyncSumSeqeunc Called"); var sum = 0; for (var i = 0; i <= count; i++) { sum = sum + i; // simulate some delay! await Task.Delay(TimeSpan.FromSeconds(0.5)); yield return sum; } }
主函數.
static async Task Main(string[] args) { const int count = 5; ConsoleExt.WriteLine("Starting Async Streams Demo!"); // Start a new task. Used to produce async sequence of data! IAsyncEnumerable<int> pullBasedAsyncSequence = ProduceAsyncSumSeqeunc(count); // Start another task; Used to consume the async data sequence! var consumingTask = Task.Run(() => ConsumeAsyncSumSeqeunc(pullBasedAsyncSequence)); await Task.Delay(TimeSpan.FromSeconds(3)); ConsoleExt.WriteLineAsync("X#X#X#X#X#X#X#X#X#X# Doing some other work X#X#X#X#X#X#X#X#X#X#"); // Just for demo! Wait until the task is finished! await consumingTask; ConsoleExt.WriteLineAsync("Async Streams Demo Done!"); }
如果一切順利,那么就能看到這樣的運行結果了.
最后,看到這就是我們想要的結果,在枚舉的基礎上,進行了異步迭代.
可以看到,整個計算過程并沒有造成主線程的阻塞,其中,值得重點關注的是紅色方框區域的線程5!線程5!線程5!線程5在請求下一個結果后,并沒有等待結果返回,而是去了Main()函數中做了別的事情,等待請求的結果返回后,線程5又接著執行foreach中任務.
Client/Server的異步拉取
如果還沒有理解Async Streams的好處,那么我借助客戶端 / 服務器端架構是演示這一功能優勢的絕佳方法。
同步調用
客戶端向服務器端發送請求,客戶端必須等待(客戶端被阻塞),直到服務器端做出響應.
示例中Yield Return就是以這種方式執行的,所以整個過程只有一個線程即線程1在處理.
異步調用
客戶端發出數據塊請求,然后繼續執行其他操作。一旦數據塊到達,客戶端就處理接收到的數據塊并詢問下一個數據塊,依此類推,直到達到最后一個數據塊為止。這正是 Async Streams 想法的來源。
最后一個示例就是以這種方式執行的,線程5詢問下一個數據后并沒有等待結果返回,而是去做了Main()函數中的別的事情,數據到達后,線程5又繼續處理foreach中的任務.
Tips
如果你使用的是.net core 2.2及以下版本,會遇到這樣的報錯.
需要安裝.net core 3.0 preview的SDK(截至至博客撰寫日期4月9日,.net core SDK最新版本為3.0.100-preview3-010431),安裝好SDK后,如果你是VS 2019正式版,可能無法選擇3.0的與預覽版,聽過只有VS 2019 Preview才支持.Net core 3.0的預覽版.
看完上述內容,你們對await foreach怎么在C# 8.0中使用有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。