我刚刚写了以下代码

public void Save()
{
   while (this.IsAsyncInProcess)
       Thread.Sleep(100);

   this.customer.OrderCount = this.orders.Count();
   this.customer.OrderTotal =  this.orders.Sum(o => x.Total);
   this.customerRepo.Save();
}

public async Task LoadAsync()
{
    this.IsAsyncInProcess = true;
    this.customer = await this.customerRepo.GetCustomerAsync(...);
    this.orders = await this.customerRepo.GetOrdersAsync(...);
    this.IsAsyncInProcess = false;
}

现在我有一个经典的死锁,因为在 this.orders 完成后,它会等待 gui 线程恢复以将 this.IsAsyncInProcess 设置为 false 。但是,Save() 里面的 gui 线程很忙

现在我将 LoadAsync 重构为
public async Task LoadAsync()
{
    await Task.Run(async () =>
    {
        this.IsAsyncInProcess = true;
        this.customer = await this.customerRepo.GetCustomerAsync(...);
        this.orders = await this.customerRepo.GetOrdersAsync(...);
        this.IsAsyncInProcess = false;
    });
}

出于兼容性原因,我不能仅仅将 Save 重构为 SaveAsync

有没有更好的方法来实现这一点,而不使用 Task.Run

最佳答案

您可以使用异步锁定。如果您无法更改 Save 的签名,那么您可以代理到异步本地函数。

static SemaphoreSlim sem = new SemaphoreSlim(1,1);

public void Save()
{
   SaveAsync();
   public async Task SaveAsync()
   {
        await sem.WaitAsync();
        try{
           this.customer.OrderCount = this.orders.Count();
           this.customer.OrderTotal =  this.orders.Sum(o => x.Total);
           this.customerRepo.Save();
        }finally{
           sem.Release();
        }
    }
}


public async Task LoadAsync()
{
    await sem.WaitAsync();
    try{
        this.customer = await this.customerRepo.GetCustomerAsync(...);
        this.orders = await this.customerRepo.GetOrdersAsync(...);
    }finally{
       sem.Release();
    }
}

甚至更好地创建自己的异步锁
static SemaphoreSlim sem = new SemaphoreSlim(1,1);

public static async Task<IDisposable> LockAsync(){
    await sem.WaitAsync();
    return Disposable.Create(()=>sem.Release());
}

public void Save()
{
   SaveAsync();
   public async Task SaveAsync()
   {
        using(await LockAsync()){
           this.customer.OrderCount = this.orders.Count();
           this.customer.OrderTotal =  this.orders.Sum(o => x.Total);
           this.customerRepo.Save();
        }
    }
}

public async Task LoadAsync()
{
    using(await LockAsync()){
        this.customer = await this.customerRepo.GetCustomerAsync(...);
        this.orders = await this.customerRepo.GetOrdersAsync(...);
    }
}

关于c# - 重构以从我的代码中删除 Taks.Run,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45791550/

10-14 17:51