C#異步迭代IAsyncEnumerable應(yīng)用實(shí)現(xiàn)
最近用WPF做金稅盤開發(fā)中有這樣一個(gè)需求,批量開票每次開票都需要連接一次金稅盤。
比如我有發(fā)票 a, b ,c ,d e 這五張發(fā)票,每次開具發(fā)票都需要調(diào)用金稅盤底層,才能正常開票。
首先,嘗試寫第一個(gè)方法
private void Button_Click(object sender, RoutedEventArgs e)
{
var dateStart = DateTime.Now; //記錄用時(shí)的起始時(shí)間
DebugText = string.Empty;
List<string> fpList = new List<string>() { "a", "b", "c", "d" };
foreach (var item in MockIO)
{
var dateEnd = DateTime.Now;
var timeSpan = dateEnd - dateStart;//記錄開票用時(shí)
DebugText += item + " " + timeSpan.TotalSeconds + "\r\n";
}
}
/// <summary>
/// 批量開票方法
/// </summary>
/// <param name="ls"></param>
/// <returns></returns>
public static IEnumerable<string> MockIO(List<string> ls)
{
foreach (var item in ls)
{
Task.Delay(1000).Wait();
yield return item;
Debug.WriteLine(Thread.GetCurrentProcessorId());
}
}
來看效果

很明顯,發(fā)生了UI阻塞情況。因?yàn)槲覀儾⑽磳?duì)代碼做任何異步處理。接下來,我們開始嘗試修改。
首先,我們嘗試按照常規(guī)異步方法修改 MockIO 函數(shù),增加 async 關(guān)鍵詞,返回結(jié)果增加 Task, 內(nèi)部對(duì)IO操作添加 await。
修改完畢后,編譯并沒有通過,VS對(duì)該方法報(bào)異常

通過提示信息,我們可以發(fā)現(xiàn),返回值 Task<IEnumerable<string>> 并不是可以迭代的,因?yàn)槲覀儾捎昧?yield 來返回值,所以我們需要一個(gè)可以迭代的返回值。
比如改成這樣

但是,這樣一次就返回一組 Task ,沒有用到方便的 yield;
此時(shí),就可以用到 IAsyncEnumerable 來設(shè)計(jì)了,IAsyncEnumerable是C# 8.0引入的新特性,在異步迭代中,非常方便。如上述代碼,可以直接修改為
public static async IAsyncEnumerable<string> MockIOAsync(List<string> ls)
{
foreach (var item in ls)
{
Task<Task<string>> task = Task<Task<string>>.Factory.StartNew(async () =>
{
await Task.Delay(1000);
return item;
});
yield return await task.Result;
}
}
我們?cè)龠\(yùn)行調(diào)試,看一下效果

我們可以看到,不僅UI沒有被阻塞,同時(shí),傳回的值也是一個(gè)接一個(gè)的傳過來的,符合我們的預(yù)期。
擴(kuò)展:雖然上述步驟我們完成的UI的非阻塞的實(shí)現(xiàn),但是我們整個(gè)開票用時(shí)并沒有節(jié)省。
接下來,我將繼續(xù)修改 MockIOAsync 方法,將實(shí)現(xiàn)迭代器內(nèi)部的多線程操作。
修改后的代碼如下
public static async Task<IEnumerable<string>> MockIOPerformanceAsync(List<string> ls)
{
List<string> lss = new List<string>();
List<Task> tasks = new List<Task>();
foreach (var item in ls)
{
Task task = new Task(() =>
{
Task.Delay(1000).Wait();
Debug.WriteLine(Thread.GetCurrentProcessorId());
lss.Add(item);
});
tasks.Add(task);
task.Start();
}
foreach (var item in tasks)
{
await item;
}
return lss;
}
效果展示:

嗯,速度很快,但是排序亂了,因?yàn)榇朔椒ㄔ诒闅v中新建了線程,list 添加并不保證按照迭代器的順序添加。有得有失。
到此這篇關(guān)于C#異步迭代IAsyncEnumerable應(yīng)用實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C#異步迭代IAsyncEnumerable內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Unity實(shí)現(xiàn)高效的音效管理類的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何通過Unity實(shí)現(xiàn)高效的音效管理類,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的可以了解一下2023-03-03
C#使用Sleep(Int32)方法實(shí)現(xiàn)動(dòng)態(tài)顯示時(shí)間
這篇文章主要為大家詳細(xì)介紹了C#如何使用Sleep(Int32)方法實(shí)現(xiàn)動(dòng)態(tài)顯示時(shí)間,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考下2024-01-01
C#中OpenCvSharp 通過特征點(diǎn)匹配圖片的方法
這篇文章主要介紹了OpenCvSharp 通過特征點(diǎn)匹配圖片的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09
C# WPF如何反射加載Geometry幾何圖形數(shù)據(jù)圖標(biāo)
這篇文章主要介紹了C# WPF如何反射加載Geometry幾何圖形數(shù)據(jù)圖標(biāo),幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下2021-03-03

