【发布时间】:2019-06-30 21:03:26
【问题描述】:
我有以下代码,我打算异步运行。我的目标是 GetPictureForEmployeeAsync() 根据需要并行调用多次。我想确保 CreatePicture 上的“等待”不会阻止我这样做。
public Task<Picture[]> GetPictures(IDictionary<string, string> tags)
{
var query = documentRepository.GetRepositoryQuery();
var employees = query.Where(doc => doc.Gender == tags["gender"]);
return Task.WhenAll(employees.Select(employee => GetPictureForEmployeeAsync(employee, tags)));
}
private Task<Picture> GetPictureForEmployeeAsync(Employee employee, IDictionary<string, string> tags)
{
var base64PictureTask = blobRepository.GetBase64PictureAsync(employee.ID.ToString());
var documentTask = documentRepository.GetItemAsync(employee.ID.ToString());
return CreatePicture(tags, base64PictureTask, documentTask);
}
private static async Task<Picture> CreatePicture(IDictionary<string, string> tags, Task<string> base64PictureTask, Task<Employee> documentTask)
{
var document = await documentTask;
return new Picture
{
EmployeeID = document.ID,
Data = await base64PictureTask,
ID = document.ID.ToString(),
Tags = tags,
};
}
如果我理解正确,Task.WhenAll() 不会受到CreatePicture() 内的两个等待任务的影响,因为GetPictureForEmployeeAsync() 没有等待。我是对的吗?如果没有,我应该如何重组代码以实现我想要的?
【问题讨论】:
-
"Task.WhenAll 不受影响" -- 以什么方式受到影响?从某种意义上说,传递给
WhenAll()的每个任务最终都会在每个等待的任务完成时完成,这肯定会受到影响。您的实现似乎是合理的(尽管有编译时错误);GetPictureForEmployee()方法返回CreatePicture()返回的任务,您通过Select()将您的输入数据投影到这些任务中创建了许多此类任务,然后您异步等待所有此类任务完成。跨度> -
说了这么多,最终还不清楚你在问什么。并行化在正确完成时与 async/await 一起工作得很好,而在不正确完成时则很差。就像其他任何事情一样。 Async/await 本身并不是真正的并行化。它可以在这种情况下使用,但它确实是一个更通用的概念,可用于 any 异步完成工作,无论是涉及并发处理某些工作集合还是单个异步操作。
-
这看起来像是 TPL DataFlow 或 RX 的案例
-
我建议你遵循在任务返回方法名称后缀
Async的约定。 -
如果您需要限制并行执行而不使用特殊解决方案(TPL 数据流、反应式扩展),这两个链接可能会有所帮助:Approaches for throttling asynchronous methods in C#、Implementing a simple ForEachAsync, part 2
标签: c# .net asynchronous asp.net-core async-await