c# - 我应该在存储库之类的地方使用 ConfigureAwait(false) 吗?
问题描述
刚刚阅读了这篇关于 ConfigureAwait 的文章,它让我想到了一个我已经有一段时间无法平静下来的问题。
考虑下面的代码。每个依赖项都用于await
使调用异步。我担心的是,每次我们退出时await
它都会返回 UI 线程,我不希望这样,直到我实际上处于需要更新 UI 以减少线程上下文切换的顶层。这让我认为ConfigureAwait(false)
应该在 UI 下方的层中使用,以避免不必要Post
的 's ( SynchronizationContext
) 到 UI 线程。
你怎么看?这是必要的还是我已经走了?或者运行时会真正为我处理这个问题吗?
没有ConfigureAwait(false)
:
public class ViewModel
{
private readonly Service service;
private readonly ICommand updateCommand;
public ViewModel(Service service)
{
this.service = service;
updateCommand = new RelayCommand(UpdateUser);
}
private async void UpdateUser()
{
Cursor.ShowWait();
await service.UpdateUser(SelectedUser);
Cursor.ShowDefault();
}
}
public class Service
{
private readonly Repository repository;
public Service(Repository repository)
{
this.repository = repository;
}
public async Task UpdateUser(Model.User user)
{
var domainUser = Convert(user);
await repository.UpdateUser(domainUser);
}
}
public class Repository
{
private readonly MyDbContext context;
public Repository(MyDbContext context)
{
this.context = context;
}
public async Task UpdateUser(User user)
{
context.Users.Update(user);
await context.SaveChangesAsync();
}
}
public class MyDbContext : DbContext
{
public DbSet<User> Users { get; set; }
}
使用 ConfigureAwait(false)
public class ViewModel
{
private readonly Service service;
private readonly ICommand updateCommand;
public ViewModel(Service service)
{
this.service = service;
updateCommand = new RelayCommand(UpdateUser);
}
private async void UpdateUser()
{
Cursor.ShowWait();
await service.UpdateUser(SelectedUser);
Cursor.ShowDefault();
}
}
public class Service
{
private readonly Repository repository;
public Service(Repository repository)
{
this.repository = repository;
}
public async Task UpdateUser(Model.User user)
{
var domainUser = Convert(user);
await repository.UpdateUser(domainUser).ConfigureAwait(false);
}
}
public class Repository
{
private readonly MyDbContext context;
public Repository(MyDbContext context)
{
this.context = context;
}
public async Task UpdateUser(User user)
{
context.Users.Update(user);
await context.SaveChangesAsync().ConfigureAwait(false);
}
}
public class MyDbContext : DbContext
{
public DbSet<User> Users { get; set; }
}
解决方案
您应该始终在库中使用 configureAwait,即使代码(在我看来)比没有代码要糟糕得多。
通过使用 ConfigureAwait,您可以启用少量的并行性:一些异步代码可以与 GUI 线程并行运行,而不是不断地用一些工作来纠缠它。
除了性能之外,ConfigureAwait 还有一个重要的方面:它可以避免死锁。
当你不能使用它时要小心:
如果在需要上下文的方法中有 await 之后的代码,则不应使用 ConfigureAwait。对于 GUI 应用程序,这包括任何操作 GUI 元素、写入数据绑定属性或依赖于 GUI 特定类型(例如 Dispatcher/CoreDispatcher)的代码。
对于 ASP.NET 应用程序,这包括使用 HttpContext.Current 或构建 ASP.NET 响应的任何代码
在存储库中,您几乎总是可以使用它,因为您不需要恢复到相同的同步上下文中。
推荐阅读
- asp.net-core - ASP.NET Core MVC - 如何在没有会话的情况下保留购物篮数据
- c# - Azure 服务总线侦听器打开太多 TCP 连接(耗尽)
- php - 在 xampp 上安装 magento 时
- django - Django Rest Framework 使用嵌套序列化器发布数据两个模型
- ros - ros-sharp 服务调用示例
- python - 如何将用户输入转换为独立的虚拟变量
- javascript - 无法使用在 Angular 7 中创建的自定义管道进行搜索
- javascript - 如何制作一个用于级联多个问题和答案的框
- .net - 有没有办法在 Kusto Data .Net 库中传输结果?
- android - 如何使用 ExoPlayer 以全屏模式显示视频?