Task.WhenAll可以通过并行而不是顺序运行任务来显著提高应用程序的性能。
这对于网络请求、文件I/O和数据库查询等I/O密集型操作特别有用。
使用Task.WhenAll的性能优势 使用Task.WhenAll通过以下方式改善性能:
示例场景: 假设你有三个任务,每个任务需要2秒钟完成。如果按顺序运行,总时间将为6秒。但是,如果使用Task.WhenAll并行运行它们,假设没有资源争用问题,总时间将只需2秒。
Task.WhenAll是.NET Core中任务并行库(TPL)提供的一个方法,它用于创建一个任务,该任务在所有提供的任务完成时完成。在需要并行运行多个异步操作并等待所有操作完成后再继续的场景中特别有用。
让我们讨论实际场景
在这种情况下,UI将比按顺序执行这些SQL获得更快的响应。
using System.Data.SqlClient;
usingSystem.Threading.Tasks;
publicclassDatabaseService
{
privatestring connectionString ="your_connection_string";
publicasyncTaskExecuteQueriesAsync(string[] queries)
{
var tasks = queries.Select(query =>ExecuteQueryAsync(query)).ToArray();
await Task.WhenAll(tasks);
}
privateasyncTaskExecuteQueryAsync(string query)
{
using(var connection =newSqlConnection(connectionString))
{
await connection.OpenAsync();
using(var command =newSqlCommand(query, connection))
{
await command.ExecuteNonQueryAsync();
}
}
}
}
考虑以下代码:
using System.IO;
usingSystem.Threading.Tasks;
publicclassIoService
{
publicasyncTaskReadFiles(string[] filePaths)
{
var tasks = filePaths.Select(filePath => Task.Run(()=> File.ReadAllText(filePath))).ToArray();
var results =await Task.WhenAll(tasks);
foreach(var content in results)
{
Console.WriteLine(content);
}
}
}
我们正在并行读取文件,UI将快速获得响应。
我们使用HttpClient对象与端点建立连接。
using System.Net.Http;
usingSystem.Threading.Tasks;
publicclassApiService
{
privatestaticreadonlyHttpClient httpClient =newHttpClient();
publicasyncTaskFetchDataFromEndpointsAsync(string[] endpoints)
{
var tasks = endpoints.Select(endpoint => httpClient.GetStringAsync(endpoint)).ToArray();
var results =await Task.WhenAll(tasks);
foreach(var result in results)
{
Console.WriteLine(result);
}
}
}
优点:与顺序下载相比,并发下载文件可以显著减少总下载时间。
using System.Net.Http;
usingSystem.Threading.Tasks;
publicclassDownloadService
{
privatestaticreadonlyHttpClient httpClient =newHttpClient();
publicasyncTaskDownloadFilesAsync(string[] urls,string destinationFolder)
{
var tasks = urls.Select(url =>DownloadFileAsync(url, destinationFolder)).ToArray();
await Task.WhenAll(tasks);
}
privateasyncTaskDownloadFileAsync(string url,string destinationFolder)
{
var fileName = Path.Combine(destinationFolder, Path.GetFileName(url));
var data =await httpClient.GetByteArrayAsync(url);
await File.WriteAllBytesAsync(fileName, data);
}
}
场景:应用程序需要执行多个独立的后台任务,如数据清理、日志记录和报告生成。
优点:并发运行后台任务确保它们更快完成,使应用程序能够更快地处理新任务。
using System.Threading.Tasks;
publicclassBackgroundTaskService
{
publicasyncTaskRunBackgroundTasksAsync()
{
var tasks =newTask[]
{
Task.Run(()=>CleanupData()),
Task.Run(()=>LogActivity()),
Task.Run(()=>GenerateReports())
};
await Task.WhenAll(tasks);
}
privatevoidCleanupData()
{
// Data cleanup logic
}
privatevoidLogActivity()
{
// Logging logic
}
privatevoidGenerateReports()
{
// Reporting logic
}
}
Task.WhenAll的异常处理 使用Task.WhenAll时,正确处理异常很重要,因为任何任务都可能失败,你需要一种方法来管理这些失败。如果任何任务失败,Task.WhenAll本身将抛出AggregateException。以下是如何以健壮的方式处理异常。
Task.WhenAll的异常处理 关键点:
示例1:Task.WhenAll的基本异常处理 这是一个演示如何处理使用Task.WhenAll时异常的简单示例:
using System;
usingSystem.Linq;
usingSystem.Threading.Tasks;
publicclassExceptionHandlingService
{
publicasyncTaskProcessTasksWithExceptionHandlingAsync()
{
var tasks =newTask[]
{
Task.Run(()=>PerformTask()),
Task.Run(()=>PerformTask()),
Task.Run(()=>PerformTask())
};
try
{
await Task.WhenAll(tasks);
}
catch(AggregateException ex)
{
foreach(var innerException in ex.InnerExceptions)
{
Console.WriteLine($"Task failed with: {innerException.Message}");
}
}
}
privatevoidPerformTask(int taskNumber)
{
if(taskNumber ==)
{
thrownewInvalidOperationException($"Task {taskNumber} encountered an error.");
}
Console.WriteLine($"Task {taskNumber} completed successfully.");
}
}
publicclassProgram
{
publicstaticasyncTaskMain(string[] args)
{
var service =newExceptionHandlingService();
await service.ProcessTasksWithExceptionHandlingAsync();
}
}
示例2:使用ContinueWith立即处理异常 这个示例演示了如何使用ContinueWith在异常发生时立即处理:
using System;
usingSystem.Linq;
usingSystem.Threading.Tasks;
publicclassImmediateExceptionHandlingService
{
publicasyncTaskProcessTasksWithImmediateExceptionHandlingAsync()
{
var tasks =newTask[]
{
Task.Run(()=>PerformTask()).ContinueWith(HandleException, TaskContinuationOptions.OnlyOnFaulted),
Task.Run(()=>PerformTask()).ContinueWith(HandleException, TaskContinuationOptions.OnlyOnFaulted),
Task.Run(()=>PerformTask()).ContinueWith(HandleException, TaskContinuationOptions.OnlyOnFaulted)
};
try
{
await Task.WhenAll(tasks);
}
catch(AggregateException ex)
{
foreach(var innerException in ex.InnerExceptions)
{
Console.WriteLine($"Task failed with: {innerException.Message}");
}
}
}
privatevoidPerformTask(int taskNumber)
{
if(taskNumber ==)
{
thrownewInvalidOperationException($"Task {taskNumber} encountered an error.");
}
Console.WriteLine($"Task {taskNumber} completed successfully.");
}
privatevoidHandleException(Task task)
{
if(task.Exception !=null)
{
foreach(var ex in task.Exception.InnerExceptions)
{
Console.WriteLine($"Handled immediately: {ex.Message}");
}
}
}
}
publicclassProgram
{
publicstaticasyncTaskMain(string[] args)
{
var service =newImmediateExceptionHandlingService();
await service.ProcessTasksWithImmediateExceptionHandlingAsync();
}
}
说明