我应该在存储库之类的地方使用ConfigureAwait(false)吗? [英] Should I use ConfigureAwait(false) in places like Repository?

查看:93
本文介绍了我应该在存储库之类的地方使用ConfigureAwait(false)吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

只需阅读有关ConfigureAwait的这篇文章,它使我想到了一个问题我已经有一段时间没有和睦了.

Just read this article about ConfigureAwait and it made me think on an issue I haven't been able to come to peace with for some time now.

请考虑以下代码.每个依赖项使用 await 进行异步调用.我担心的是,每次我们退出 await 时,它都会返回到UI线程,直到我实际上处于需要更新UI以便进行更新的顶层时,我才希望这样做减少线程上下文切换.这使我认为应该在UI下方的层中使用 ConfigureAwait(false),以避免不必要的 Post 的( SynchronizationContext )到UI线程.

Consider the code below. Each dependency uses await to make the call asynchronous. My concern is that each time we exit an await it goes back to the UI thread and I don't want that until I'm actually at the top level where the UI needs to be updated in order to reduce thread context switching. That made me think that ConfigureAwait(false) should be used in layers below the UI to avoid unnecessary Post's (SynchronizationContext) to the UI thread.

您怎么看?这是必要的还是我要离开?还是运行时会真正为我解决这个问题?

What do you think? Is this necessary or am I way off? Or will the runtime actually take care of this for me?

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.

You should always use configureAwait in libraries, even if the code (in my opinion) is much worse than without.

通过使用ConfigureAwait,您可以启用少量并行操作:某些异步代码可以与GUI线程并行运行,而不必不断地为其添加工作标记.

By using ConfigureAwait, you enable a small amount of parallelism: Some asynchronous code can run in parallel with the GUI thread instead of constantly badgering it with bits of work to do.

除了性能之外,ConfigureAwait还有另一个重要方面:它可以避免死锁.

Aside from performance, ConfigureAwait has another important aspect: It can avoid deadlocks.

当您不能使用它时要小心:

Be careful of when you can't use it:

在需要上下文的方法中,在等待之后有代码时,不应使用ConfigureAwait.对于GUI应用程序,这包括操纵GUI元素,编写数据绑定属性或依赖于特定于GUI的类型(例如Dispatcher/CoreDispatcher)的任何代码.

You should not use ConfigureAwait when you have code after the await in the method that needs the context. For GUI apps, this includes any code that manipulates GUI elements, writes data-bound properties or depends on a GUI-specific type such as Dispatcher/CoreDispatcher.

对于ASP.NET应用程序,这包括使用HttpContext.Current或构建ASP.NET响应的任何代码

For ASP.NET apps, this includes any code that uses HttpContext.Current or builds an ASP.NET response

在存储库中,几乎总是可以使用它,因为您无需恢复到相同的同步上下文中.

In repositories, it's almost always the case that you can use it as you don't need to resume into the same Synchronization context.

这篇关于我应该在存储库之类的地方使用ConfigureAwait(false)吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆