我有EF助手类,可以保存更改异步:
public async Task<int> SaveOrUpdateAsync<TEntity>(TEntity entity)
where TEntity : class, IContextEntity
{
if (entity.Id == 0)
context.Set<TEntity>().Add(entity);
else
{
TEntity dbEntry = context.Set<TEntity>().Find(entity.Id);
if (dbEntry != null) dbEntry = entity;
}
return await context.SaveChangesAsync();
}
public void Save()
{
Task saveEntit1Async = repository.SaveOrUpdateAsync<Entity1>(entity1);
Task saveEntity2Async = repository.SaveOrUpdateAsync<Entity2>(entity2);
Task saveEntity3Async = repository.SaveOrUpdateAsync<Entity3>(Entity3);
Task.WaitAll(saveEntit1Async, saveEntity2Async, saveEntity3Async);
string test = "test";
)
电话卡在
上Task.WaitAll(saveEntit1Async, saveEntity2Async, saveEntity3Async);
一行,永远不会到达
string test = "test";
但如果我将其作为:
运行public void Save()
{
repository.SaveOrUpdateAsync<Entity1>(entity1);
repository.SaveOrUpdateAsync<Entity2>(entity2);
repository.SaveOrUpdateAsync<Entity3>(Entity3);
string test = "test";
)
它工作正常,所有更改都被保存并且到达
string test = "test";
为什么
Task.WaitAll(saveEntit1Async, saveEntity2Async, saveEntity3Async);
冻结操作并且永远不会将调用传递给下一行代码(字符串测试=&#34;测试&#34 ;;)?
答案 0 :(得分:14)
我明白了!
以下是发生的问题,当您使用“等待”方法等待任务或直接从任务的“结果”属性获取结果时,您阻止主线程 同时。当最终任务在线程池中的该方法(SaveOrUpdateAsync(TEntity entity))内完成时,它将调用continuation以回发到主线程(因为它从未离开它),因为SynchronizationContext.Current可用并被捕获。但这是一个问题:主线程被“等待”方法阻止,这就是我陷入僵局的方式!
要修复死锁问题,我必须指定不继续捕获context.SaveChangesAsync()的上下文。
public async Task<int> SaveOrUpdateAsync<TEntity>(TEntity entity)
where TEntity : class, IContextEntity
{
if (entity.Id == 0)
context.Set<TEntity>().Add(entity);
else
{
TEntity dbEntry = context.Set<TEntity>().Find(entity.Id);
if (dbEntry != null) dbEntry = entity;
}
return await context.SaveChangesAsync().ConfigureAwait(continueOnCapturedContext: false);
}
答案 1 :(得分:0)
也许我是傻瓜(!),但为什么你的代码会说
if (dbEntry != null) dbEntry = entity;
肯定if语句应该是
if (dbEntry == null) dbEntry = entity;
我猜C#null-coalescing运算符也可以替换两行
TEntity dbEntry = context.Set<TEntity>().Find(entity.Id) ?? entity;