当执行长时间运行的操作时,我注意到我可以在起始行开始执行长时间运行的子操作,并在从缓存/数据库中获取结果时执行其他操作。
给定的操作是:
public async Task<Fichaclis> Finalize()
{
using (TransactionScope transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
transactionTimer.Start();
var agendasTransitionTask = ExecuteAgendas();
... DO ALOT OF SYNC OPERATIONS ...
await agendasTransitionTask;
transaction.Complete();
}
}
private Task ExecuteAgendas()
{
return ags.GetAgendas().ContinueWith((prev) =>
{
var currentAgendas = prev.Result;
foreach (var item in currentAgendas)
{
... DO QUICK SYNC STUFF...
}
return ags.BulkEditAgenda(currentAgendas);
});
}
GetAgendas是一种全部使用的方法,具有以下签名:
public async Task<List<Agendas>> GetAgendas()
因为它被广泛使用,我相信问题不存在。至于BulkEditAgenda
:
public async Task BulkEditAgenda(IEnumerable<Agendas> agendas)
{
if (agendas == null || agendas.Count() == 0)
{
return;
}
var t1 = AddOrUpdateCache(agendas);
var t2 = Task.Factory.StartNew(() =>
{
try
{
foreach (var item in agendas)
{
EditNoReconnection(item);
}
Save();
}
catch (Exception ex)
{
//log
throw;
}
});
await Task.WhenAll(t1, t2);
}
EditNoReconnect
和Save
都是同步方法。
private Task AddOrUpdateCache(IEnumerable<Agendas> agendas)
{
var tasks = new List<Task>();
foreach (var item in agendas)
{
tasks.Add(TryGetCache(item)
.ContinueWith((taskResult) =>
{
...DO QUICK SYNC STUFF...
})
);
}
return Task.WhenAll(tasks);
}
TryGetCache
也是一种广泛使用的方法,所以我觉得它很安全......它的签名是private Task<AgendasCacheLookupResult> TryGetCache(
因此,恢复手头的问题:对于Finalize
方法的同步会话中的一小组项,命令transaction.Complete()
在Save()
之前执行(在BulkEditAgendas内)。对于常规或大量的项目,它按预期工作
这意味着我没有正确地链接Tasks
,或者我对Async / Await + Tasks / ContinueWith如何工作的理解从根本上说是不正确的。我哪里错了?
答案 0 :(得分:6)
问题很可能在这里:
private Task ExecuteAgendas()
{
return ags.GetAgendas().ContinueWith((prev) =>
{
var currentAgendas = prev.Result;
foreach (var item in currentAgendas)
{
... DO QUICK SYNC STUFF...
}
return ags.BulkEditAgenda(currentAgendas);
});
}
首先,你从中返回的是继续任务(ContinueWith
的结果)。但是ContinueWith
的主体在你做
return ags.BulkEditAgenda(currentAgendas);
因此,在 BulkEditAgenda
任务完成之前,延续体可能结束(您不会以任何方式等待完成BulkEditAgenda
)。所以这一行
await agendasTransitionTask;
BulkEditAgenda
仍在进行中时返回。为了进一步说明,请注意ExecuteAgendas
返回的内容为Task<Task>
,await agendasTransitionTask
的结果为Task
,代表您正在投放BulkEditAgenda
。
要修复,只需像在其他地方一样使用async \ await:
private async Task ExecuteAgendas() {
var currentAgengas = await ags.GetAgendas();
foreach (var item in currentAgendas) {
// do stuff
}
await ags.BulkEditAgenda(currentAgendas);
}