C# 异步/等待并行化是如何工作的?
我准备异步运行以下代码。我的目标是根据需要并行调用C# 异步/等待并行化是如何工作的?,c#,.net,asynchronous,asp.net-core,async-await,C#,.net,Asynchronous,Asp.net Core,Async Await,我准备异步运行以下代码。我的目标是根据需要并行调用GetPictureForEmployeeAsync()。我想确保CreatePicture上的“等待”不会阻止我这样做 public Task<Picture[]> GetPictures(IDictionary<string, string> tags) { var query = documentRepository.GetRepositoryQuery(); var
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,
};
}
public任务GetPictures(IDictionary标记)
{
var query=documentRepository.GetRepositoryQuery();
var employees=query.Where(doc=>doc.Gender==标记[“Gender”]);
返回Task.WhenAll(employee.Select(employee=>GetPictureForEmployeeAsync(employee,tags));
}
私有任务GetPictureForEmployeeAsync(员工,IDictionary标记)
{
var base64PictureTask=blobRepository.GetBase64PictureAsync(employee.ID.ToString());
var documentTask=documentRepository.GetItemAsync(employee.ID.ToString());
返回CreatePicture(标签、base64PictureTask、documentTask);
}
专用静态异步任务CreatePicture(IDictionary标记、Task base64PictureTask、Task documentTask)
{
var document=等待documentTask;
返回新图片
{
EmployeeID=document.ID,
数据=等待base64PictureTask,
ID=document.ID.ToString(),
标签=标签,
};
}
如果我理解正确,
Task.WhenAll()
不受CreatePicture()
中两个等待的任务的影响,因为GetPictureForEmployeeAsync()
没有等待。我说的对吗?如果没有,我应该如何重新构造代码以实现我想要的功能?调用异步方法时要记住的一点是,只要在该方法中到达wait
语句,control立即返回调用异步方法的代码,不管await语句在方法中的什么位置。对于“普通”方法,控件不会返回调用该方法的代码,直到到达该方法的末尾
因此,在您的情况下,您可以执行以下操作:
private异步任务GetPictureForEmployeeAsync(雇员-雇员,IDictionary标记)
{
//我们一到这里,控制就立即返回到GetPictures
//方法--不需要将任务存储在变量中并在变量中等待它
//按您所做的方式创建图片
var picture=await blobRepository.GetBase64PictureAsync(employee.ID.ToString());
var document=await documentRepository.GetItemAsync(employee.ID.ToString());
返回CreatePicture(标签、图片、文档);
}
因为GetPictureForEmployeeAsync中的第一行代码有一个wait
,所以控件将立即返回这一行
returntask.WhenAll(employees.Select(employee=>GetPictureForEmployeeAsync(employees,tags));
…一旦被调用。这将产生并行处理所有员工项目的效果(嗯,有点——分配给应用程序的线程数量是有限的)
另外一条建议是,如果此应用程序正在访问数据库或web服务以获取图片或文档,则此代码可能会导致您出现可用连接不足的问题。如果是这种情况,考虑使用<代码>系统。线程。任务。并行< /代码>并设置最大并行度,或者使用<代码> SimaPraceSimLime/Cult>来控制同时使用的连接数量。
我想确保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()未被等待。我说的对吗
是和否。whalll
不受CreatePicture
中等待的任务的任何限制,但这与是否等待GetPictureForEmployeeAsync
无关。这两行代码在行为方面是等效的:
return Task.WhenAll(employees.Select(employee => GetPictureForEmployeeAsync(employee, tags)));
return Task.WhenAll(employees.Select(async employee => await GetPictureForEmployeeAsync(employee, tags)));
我建议阅读我的,以便更好地了解async
和wait
如何处理任务
此外,由于GetPictures
具有非平凡的逻辑(GetRepositoryQuery
和评估标记[“性别”]
),因此GetPictures
的I为:
public async Task<Picture[]> GetPictures(IDictionary<string, string> tags)
{
var query = documentRepository.GetRepositoryQuery();
var employees = query.Where(doc => doc.Gender == tags["gender"]);
var tasks = employees.Select(employee => GetPictureForEmployeeAsync(employee, tags)).ToList();
return await Task.WhenAll(tasks);
}
“Task.WhenAll不受影响”--以何种方式受影响?当每个等待的任务完成时,传递给
WhenAll()
的每个任务最终都会完成,从这个意义上说,这肯定会受到影响。您的实现似乎是合理的(尽管存在编译时错误);GetPictureForEmployee()
方法返回由CreatePicture()
返回的任务,通过Select()
将输入数据投影到这些任务,您可以创建许多这样的任务,然后异步等待所有这样的任务完成,最终,你问的问题并不十分清楚。当异步/等待操作正确时,并行化可以很好地工作,反之则很差。就像其他事情一样。Async/await本身并不是真正的并行化。它可以在这样的环境中使用,但对于任何异步完成的工作来说,它实际上是一个更一般的概念,无论是涉及到一些工作集合的并发处理还是单个异步操作。这看起来像是TPL数据流的情况,或者RXI建议您遵循使用Async
作为任务返回方法名称后缀的惯例。如果您需要限制并行执行而不诉诸外来解决方案(TPL数据流、反应式扩展),这两个链接可能会很有帮助:,请注意,您提出的替代方案具有显著的,坦率地说,它改变了OP代码的语义。特别是,虽然原始代码是根据