多个异步方法,最好将 WhenAll 与不同的 return 类型一起使用
Multiple Async Methods, best to use WhenAll with different return types
我有一个异步控制器操作方法,它在我的后端调用 4 个异步方法以从每个 return 列表。每种方法的对象列表都不同。即List列表等
我是这样工作的:
BizProvider bp = new BizProvider();
List<biz.Customer> custReturn = await bp.GetCustomerAsync();
List<biz.Account> acctReturn = await bp.GetAccountAsync();
...plus 2 more
List<object> returnArr = new List<object>();
returnArr.Add(custReturn);
returnArr.Add(acctReturn); ...plus 2 more
return JsonConvert.SerializeObject(returnArr);
因为有多个任务,我应该使用 Task.WhenAll
吗?
微软的例子
https://msdn.microsoft.com/en-us/library/hh194874%28v=vs.110%29.aspx
所有任务returnList<int>
所以我使用和抽象 class 并让我所有的列表对象类型都继承自它。
我将我的业务对象提供者的 return 类型更改为 return 抽象类型列表
所以现在我可以做:
var tasks1 = new List<Task<List<Biz.AbstractClass>>>();
tasks1.Add(bp.GetCustomerAsAbstractAsync());
tasks1.Add(bp.GetAccountAsAbstractAsync());
...plus 2 more
然后我打电话
var continuation = Task.WhenAll(tasks1);
这执行然后下一行它到达 .Results
但随后停止执行???
foreach (var result in continuation.Result)
^ stops here
我再打电话给
returnArrays.Add(result1);
return JsonConvert.SerializeObject(returnArrays);
但是这些从来没有被击中...我不知道为什么。
也许我不需要WhenAll
,但我仍然很好奇出了什么问题。
也许我需要等待特定函数,或者以某种方式调用 Action,因为在 Microsoft link 中函数被称为内联。
Task.Run(async () => { x=x,etc...)
编辑 20150306 => 添加更多实施细节
CustMan cm = new CustMan();
List<object> returnArr = new List<object>();
var aTask = cm.GetCustomersAsync();
var bTask = cm.GetAccountsAsync();
await Task.WhenAll(aTask, bTask);
returnArr.Add(aTask.Result);//same for bTask <-- breakpoint never hits
return JsonConvert.SerializeObject(returnArr);
//also .js ajax return method never comes back.
//in CustMan()
public async Task<List<biz.Customer>> GetCustomersAsync() {
List<biz.Customer> custList = await (from contact in ObjectContextDb.GetData<da.ContactInfo>()//<--generic returns IQueryable
join customerContact in ObjectContextDb.GetData<da.CustomerContact>() on contact.Id equals customerContact.ContactInfoID
join customerOrg in ObjectContextDb.GetData<da.CustomerOrganisation>() on customerContact.OrgID equals customerOrg.Id
orderby contact.LastName
select new biz.Customer {
CustomerContactInfo = new biz.Contact() {
ID = contact.Id,
WorkPhone = contact.WorkPhone
},
CustomerOrg = new biz.CustomerOrganisation {
ID = facultyOrg.Id,
Name = facultyOrg.OrgName,
ClientID = (customerContact.ClientID.HasValue ? customerContact.ClientID.Value : 0)
}
}).ToListAsync<biz.Customer>();
return custList;// <-- Breakpoint hits here, the List has items
}
public async Task<List<biz.Account>> GetAccountsAsync()
{
var roles = (from acctType in ObjectContextDb.GetData<da.AccountInType>()
join r in ObjectContextDb.GetData<da.AccountType>() on acctType.AccountTypeID equals r.ID
select new
{
AccountId = acctType.AccountID,
Type = r.TypeName
}); //.ToList();
List<biz.Account> allContacts = await (from account in ObjectContextDb.GetData<da.Account>()
orderby account.Name
select new biz.Account()
{
Number = account.Id,
Name = account.Name,
Roles = (from r in roles where account.Id == r.AccountId select r.Type).ToList()
}).ToListAsync<biz.Account>();
return allContacts;// <-- Breakpoint hits here, the List has items
}
在没有 WhenAll
的情况下调用管理器 Class 方法的方法有效!
CustMan cm = new CustMan();
List<object> returnArrays = new List<object>();
List<biz.Customer> custReturn = await cm.GetCustomersAsync();
List<biz.Account> acctReturn = await cm.GetAccountsAsync();
returnArrays.Add(custReturn);
returnArrays.Add(acctReturn);
return JsonConvert.SerializeObject(returnArrays);
听起来你正在这样做:
var continuation = Task.WhenAll(tasks1);
foreach (var result in continuation.Result) { }
这可能是 deadlocking。 WhenAll
returns 一个 Task
,所以你需要 await
那:
var results = await Task.WhenAll(tasks1);
foreach (var result in results) { }
否则,构建 List
个任务并将它们传递给 WhenAll
是同时等待多个任务的完全合理的方式。
您可以使用 Task.WhenAll
而无需更改任何内容。只需将任务存储在一个变量中,然后添加它们的结果:
var aTask = GetAAsync();
var bTask = GetBAsync();
...
await Task.WhenAll(aTask, bTask);
returnArr.Add(aTask.Result);
returnArr.Add(bTask.Result);
然而,在你的情况下,异步操作使用 Entity Framework 其中 doesn't support multiple operations concurrently 所以你不能那样做。
一次呼叫并等待您的操作:
returnArr.Add(await GetAAsync());
returnArr.Add(await GetBAsync());
...
我有一个异步控制器操作方法,它在我的后端调用 4 个异步方法以从每个 return 列表。每种方法的对象列表都不同。即List列表等
我是这样工作的:
BizProvider bp = new BizProvider();
List<biz.Customer> custReturn = await bp.GetCustomerAsync();
List<biz.Account> acctReturn = await bp.GetAccountAsync();
...plus 2 more
List<object> returnArr = new List<object>();
returnArr.Add(custReturn);
returnArr.Add(acctReturn); ...plus 2 more
return JsonConvert.SerializeObject(returnArr);
因为有多个任务,我应该使用 Task.WhenAll
吗?
微软的例子 https://msdn.microsoft.com/en-us/library/hh194874%28v=vs.110%29.aspx
所有任务returnList<int>
所以我使用和抽象 class 并让我所有的列表对象类型都继承自它。 我将我的业务对象提供者的 return 类型更改为 return 抽象类型列表 所以现在我可以做:
var tasks1 = new List<Task<List<Biz.AbstractClass>>>();
tasks1.Add(bp.GetCustomerAsAbstractAsync());
tasks1.Add(bp.GetAccountAsAbstractAsync());
...plus 2 more
然后我打电话 var continuation = Task.WhenAll(tasks1);
这执行然后下一行它到达 .Results
但随后停止执行???
foreach (var result in continuation.Result)
^ stops here
我再打电话给
returnArrays.Add(result1);
return JsonConvert.SerializeObject(returnArrays);
但是这些从来没有被击中...我不知道为什么。
也许我不需要WhenAll
,但我仍然很好奇出了什么问题。
也许我需要等待特定函数,或者以某种方式调用 Action,因为在 Microsoft link 中函数被称为内联。
Task.Run(async () => { x=x,etc...)
编辑 20150306 => 添加更多实施细节
CustMan cm = new CustMan();
List<object> returnArr = new List<object>();
var aTask = cm.GetCustomersAsync();
var bTask = cm.GetAccountsAsync();
await Task.WhenAll(aTask, bTask);
returnArr.Add(aTask.Result);//same for bTask <-- breakpoint never hits
return JsonConvert.SerializeObject(returnArr);
//also .js ajax return method never comes back.
//in CustMan()
public async Task<List<biz.Customer>> GetCustomersAsync() {
List<biz.Customer> custList = await (from contact in ObjectContextDb.GetData<da.ContactInfo>()//<--generic returns IQueryable
join customerContact in ObjectContextDb.GetData<da.CustomerContact>() on contact.Id equals customerContact.ContactInfoID
join customerOrg in ObjectContextDb.GetData<da.CustomerOrganisation>() on customerContact.OrgID equals customerOrg.Id
orderby contact.LastName
select new biz.Customer {
CustomerContactInfo = new biz.Contact() {
ID = contact.Id,
WorkPhone = contact.WorkPhone
},
CustomerOrg = new biz.CustomerOrganisation {
ID = facultyOrg.Id,
Name = facultyOrg.OrgName,
ClientID = (customerContact.ClientID.HasValue ? customerContact.ClientID.Value : 0)
}
}).ToListAsync<biz.Customer>();
return custList;// <-- Breakpoint hits here, the List has items
}
public async Task<List<biz.Account>> GetAccountsAsync()
{
var roles = (from acctType in ObjectContextDb.GetData<da.AccountInType>()
join r in ObjectContextDb.GetData<da.AccountType>() on acctType.AccountTypeID equals r.ID
select new
{
AccountId = acctType.AccountID,
Type = r.TypeName
}); //.ToList();
List<biz.Account> allContacts = await (from account in ObjectContextDb.GetData<da.Account>()
orderby account.Name
select new biz.Account()
{
Number = account.Id,
Name = account.Name,
Roles = (from r in roles where account.Id == r.AccountId select r.Type).ToList()
}).ToListAsync<biz.Account>();
return allContacts;// <-- Breakpoint hits here, the List has items
}
在没有 WhenAll
的情况下调用管理器 Class 方法的方法有效!
CustMan cm = new CustMan();
List<object> returnArrays = new List<object>();
List<biz.Customer> custReturn = await cm.GetCustomersAsync();
List<biz.Account> acctReturn = await cm.GetAccountsAsync();
returnArrays.Add(custReturn);
returnArrays.Add(acctReturn);
return JsonConvert.SerializeObject(returnArrays);
听起来你正在这样做:
var continuation = Task.WhenAll(tasks1);
foreach (var result in continuation.Result) { }
这可能是 deadlocking。 WhenAll
returns 一个 Task
,所以你需要 await
那:
var results = await Task.WhenAll(tasks1);
foreach (var result in results) { }
否则,构建 List
个任务并将它们传递给 WhenAll
是同时等待多个任务的完全合理的方式。
您可以使用 Task.WhenAll
而无需更改任何内容。只需将任务存储在一个变量中,然后添加它们的结果:
var aTask = GetAAsync();
var bTask = GetBAsync();
...
await Task.WhenAll(aTask, bTask);
returnArr.Add(aTask.Result);
returnArr.Add(bTask.Result);
然而,在你的情况下,异步操作使用 Entity Framework 其中 doesn't support multiple operations concurrently 所以你不能那样做。
一次呼叫并等待您的操作:
returnArr.Add(await GetAAsync());
returnArr.Add(await GetBAsync());
...