【问题标题】:Wait on async lambda with Partial async/await code in ASP.NET 4.5在 ASP.NET 4.5 中使用部分异步/等待代码等待异步 lambda
【发布时间】:2014-05-06 17:01:05
【问题描述】:

我在 asp.net 中有一个 HTTPHandler,我想使用 4.5 异步等待代码将其转换为异步。然而,并非我们所有的代码都是 4.5,因此我们应用程序的内部部分(库、基础设施)目前需要保持在 4.0。我遇到了一个问题,我想为我们的一些共享库提供一个 lambda。 lambda 是异步的,但我需要库代码来等待它完成,但没有死锁。到目前为止,我还没有弄明白。

假设处理程序如下所示:

// .NET 4.5 website
public class MyHandler : HttpTaskAsyncHandler
{
    public override async Task ProcessRequestAsync(HttpContext context)
    {
         var someLibrary = new SharedLibrary();
         someLibrary.PostProcess = async (x,y) => {
             await ProcessXY(x,y);
         }

         await someLibrary.ProcessAsync();
         // write out some content here
    }

    private async Task ProcessXY(int x, int y) {
        // make some external calls
        var someLib = new SomeOtherLibrary();
        await someLib.CallAsync(x,y);
    }
}

然后 SharedLibrary 看起来像这样:

// .NET 4.0 class library
public class SharedLibrary {
    public Action<int,int> PostProcess { get; set; }

    public Task ProcessAsync() {
        return Task.Factory.StartNew(() => Process(), CancellationToken.None,TaskCreationOptions.None,TaskScheduler.FromCurrentSynchronizationContext());
    }

    public void Process() {
       // do some processing
       if (PostProcess != null) {
           // call PostProcess synchronously
           PostProcess(1,2);
       }
       // do some final processing
    }
}

就目前的代码而言,对 PostProcess 的调用在 lambda 完全运行完成之前返回。如果我将 PostProcess 切换到 Func&lt;int,int,Task> 并调用为 PostProcess(1,2).Wait() 那么我会死锁。有没有办法在这样的混合 4.5/4.0 代码中完成?

【问题讨论】:

  • 你可以在.NET 4.0中使用await,只要你还在使用C# 5.0,即使你不能使用await,你仍然可以在.NET中编写异步程序4.0,这只是要做更多的工作,并且做得很好。您的 4.0 代码不需要是同步的。
  • 尝试给 Process 方法一个返回类型,我认为会强制运行时等待它实际返回。 msdn.microsoft.com/en-us/library/…
  • 需要ProcessXY// do some final processing之前完成,还是只需要在// write out some content here之前完成?
  • 是 ProcessXY 需要在最终处理之前完成。 Process 获取分布式锁(这不是 CLR 锁),PostProcess 对数据进行一些额外的修改。最后的处理是保存然后释放锁。

标签: c# asp.net .net-4.0 async-await .net-4.5


【解决方案1】:

在你的 lambda 中使用 ConfigureAwait(false)

public override async Task ProcessRequestAsync(HttpContext context)
{
     var someLibrary = new SharedLibrary();
     someLibrary.PostProcess = async (x,y) => {
         await ProcessXY(x,y).ConfigureAwait(false);
     }

     await someLibrary.ProcessAsync();
     // write out some content here
}

public class SharedLibrary {
  public Func<int,int,Task> PostProcess { get; set; }

  public void Process() {
   // do some processing
    if (PostProcess != null) {
       // call PostProcess synchronously
       PostProcess(1,2).Wait();
    }
   // do some final processing
  }
}

这样你应该避免在 UI 线程上死锁。

编辑

如 cmets 所述,一旦在 ASP.NET 中使用了 ConfigureAwait(false),则 HttpContext 在 continuation 中不再可用 (await之后的代码)

我建议您查看通过 Nuget 为 .NET 4 部署的 Microsoft.Bcl.Async 库,这样您就可以正确使用 async/await 而无需无缘无故地初始化线程:

http://blogs.msdn.com/b/bclteam/p/asynctargetingpackkb.aspx

【讨论】:

  • 这行得通。需要注意的一点是,由于 ConfigureAwait(false),lambda 将无法访问 ASP.NET 上下文。幸运的是,在这种情况下我可以解决这个问题。
  • 对了,我忘了说!编辑了我的帖子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-22
  • 1970-01-01
  • 2012-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
相关资源
最近更新 更多