我正在尝试优化此代码以减少完成for
循环所需的时间。在这种情况下,CreateNotification()
需要很长时间,并且使用async
await
并不会提高性能,因为正在等待每个异步调用。我想使用Task.WhenAll()
来优化代码。我怎样才能做到这一点?
foreach (var notification in notificationsInput.Notifications)
{
try
{
var result = await CreateNotification(notification);
notification.Result = result;
}
catch (Exception exception)
{
notification.Result = null;
}
notifications.Add(notification);
}
答案 0 :(得分:3)
您可以在要并行处理其元素的集合上调用Select
,并将异步委托传递给它。此异步委托将为每个已处理的元素返回Task
,因此您可以在所有这些任务上调用Task.WhenAll
。模式是这样的:
var tasks = collection.Select(async (x) => await ProcessAsync(x));
await Task.WhenAll(tasks);
对于你的例子:
var tasks = notificationsInput.Notifications.Select(async (notification) =>
{
try
{
var result = await CreateNotification(notification);
notification.Result = result;
}
catch (Exception exception)
{
notification.Result = null;
}
});
await Task.WhenAll(tasks);
这假定CreateNotification
是线程安全的。
答案 1 :(得分:1)
更新
您需要安装DataFlow才能使用此解决方案
https://www.nuget.org/packages/System.Threading.Tasks.Dataflow/
取决于CreateNotification
是什么以及是否要并行运行。
您可以使用DataFlow ActionBlock
,如果这是 IO绑定或Mix IO / CPU绑定操作,它将为您提供两全其美的优势让你运行async
并行并行
public static async Task DoWorkLoads(NotificationsInput notificationsInput)
{
var options = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 50
};
var block = new ActionBlock<Something>(MyMethodAsync, options);
foreach (var notification in notificationsInput.Notifications)
block.Post(notification);
block.Complete();
await block.Completion;
}
...
public async Task MyMethodAsync(Notification notification)
{
var result = await CreateNotification(notification);
notification.Result = result;
}
加入胡椒和盐调味。
答案 2 :(得分:1)
我认为这应该等同于你的代码:
var notifications = new ConcurrentBag<Notification>();
var tasks = new List<Task>();
foreach (var notification in notificationsInput.Notifications)
{
var task = CreateNotification(notification)
.ContinueWith(t =>
{
if (t.Exception != null)
{
notification.Result = null;
}
else
{
notification.Result = t.Result;
}
notifications.Add(notification);
});
tasks.Add(task);
}
await Task.WhenAll(tasks);
.ContinueWith(
将从CreateNotification(
收到已完成/失败的任务,并且本身就是一项任务。我们将ContinueWith
任务添加到列表中,并在WhenAll(
中使用该任务。
我使用ConcurrentBag
进行通知,以便您可以安全地从多个线程添加。如果要将其转换为常规列表,可以调用var regularListNotifications = notifications.ToList();
(假设您使用LINQ)。