我希望有人澄清等待許多任務和手動等待它們在集合中完成之間的區別。
我有一個 XML 閱讀器類,它必須處理數百個檔案,在優化它時我發現了一個有趣的區別。我創建了兩個函式,它們都呼叫了我的
private async Task ParseModelsFromFile(ConcurrentDictionary<TSettings, TResults> datas, string filePath)函式。這基本上從給定的 XML 檔案中加載了我的所有模型filePath。唯一的區別在于這個ParseModelsFromFile()函式的呼叫和等待。
第一個函式:ProcessFiles()使用await關鍵字,第二個函式:為每個 singleProcessFilesWithTasks創建一個物件,將其放入 s 的集合中并等待它們全部完成。TaskfilePathTask
帶有任務集合的第二個版本要快得多。大約需要一半的時間。我在想這兩個函式會做同樣的事情,唯一的區別是async關鍵字的使用。
我確實用幾個檔案對此進行了測驗,使用 await 的函式總是慢 2 倍左右。
private async Task ProcessFiles(ConcurrentDictionary<TSettings, TResults> datas, BlockingCollection<string> filePaths)
{
if (filePaths.Count == 0)
return;
foreach (var filePath in filePaths.GetConsumingEnumerable())
{
await ParseModelsFromFile(datas, filePath);
}
}
private Task ProcessFilesWithTasks(ConcurrentDictionary<TSettings, TResults> datas, BlockingCollection<string> filePaths)
{
if (filePaths.Count == 0)
return Task.CompletedTask;
List<Task> runningTasks = new List<Task>();
foreach (var filePath in filePaths.GetConsumingEnumerable())
{
runningTasks.Add(ParseModelsFromFile(datas, filePath));
}
Task allTasks = Task.WhenAll(runningTasks.ToArray());
allTasks.Wait();
return Task.CompletedTask;
}
uj5u.com熱心網友回復:
如果您了解異步代碼的作業原理,您就會明白為什么。那么我們先來看看有什么ParseModelsFromFile作用。當它被呼叫時,它會一直運行到該await方法中的第一個,這可能是它讀取檔案的地方。在作業系統和硬體出去讀取檔案期間,您的應用程式無事可做。正是在這一點上ParseModelsFromFile 回傳。它回傳 a Task,您可以使用它來了解該方法的其余部分何時完成。
知道了這一點,我們可以談談您的兩個實作之間的區別:
使用await方法:在此任務完成之前不要做任何事情。執行緒被釋放來做其他事情,這是異步編程的好處。但是您的方法的執行會停止,直到任務完成。因此,await在回圈內部使用foreach將處理一個檔案并等待它完全處理,然后再移動到回圈的下一次迭代。
而在 中ProcessFilesWithTasks,因為您在await呼叫時沒有使用,所以您ParseModelsFromFile使用的是作業系統正在檢索檔案以移動到回圈的下一個迭代并開始ParseModelsFromFile為下一個檔案運行的時間。
如果這是在沒有同步背景關系的應用程式中(例如 ASP.NET Core、控制臺或 Windows 服務),那么每次呼叫ParseModelsFromFile(第一個之后的所有內容)的延續await將在不同的執行緒上運行,這將也使每個檔案的處理速度更快。
我要做的唯一改變是制作ProcessFilesWithTasks async和使用awaitonTask.WhenAll()而不是.Wait():
private async Task ProcessFilesWithTasks(ConcurrentDictionary<TSettings, TResults> datas, BlockingCollection<string> filePaths)
{
if (filePaths.Count == 0)
return Task.CompletedTask;
List<Task> runningTasks = new List<Task>();
foreach (var filePath in filePaths.GetConsumingEnumerable())
{
runningTasks.Add(ParseModelsFromFile(datas, filePath));
}
await Task.WhenAll(runningTasks);
}
Wait()將阻止執行緒做任何其他事情。它只會閑置。Usingawait將釋放執行緒在等待時做其他事情。
你也不需要打電話,.ToArray()因為Task.WhenAll()接受IEnumerable<Task>,List<Task>就是這樣。
微軟有一些寫得很好的關于異步編程的文章,我認為你會從閱讀中受益。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/429168.html
上一篇:c#和python中解碼的不同值
