为什么等待从异步方法返回的任务会被阻塞

本文关键字:任务 等待 异步方法 返回 为什么 | 更新日期: 2023-09-27 18:17:35

我正在做一个Nancy/ASP。网络项目。我试图使用WebRequest从其他web服务获取数据,我已经在异步函数中实现了请求。我发现一个问题,当我试图等待从函数返回的任务时,它会被无限期地阻塞。简化后的代码如下:

using System.Net;
using System.Threading.Tasks;
using Nancy;
public class TestModule : NancyModule{
    public TestModule() {
        Get["/"] = p => "Hello, world";
        Get["/async/"] = p => {
            var req = WebRequest.CreateHttp("http://localhost:13254/");
//          var responseTask = req.GetResponseAsync();  // this works!
            var responseTask = getResponse(req);   // this gets blocked!
            var waitSuccess = responseTask.Wait(10000);
            return waitSuccess ? "Yeah!" : "woooh!";
        };
    }
    async Task<HttpWebResponse> getResponse(HttpWebRequest request) {
        return (HttpWebResponse) await request.GetResponseAsync();
    }
}

代码使用NancyFx,但它也发生在香草ASP。网络页面。localhost:13254上的服务工作正常。如果我使用从请求的GetResponseAsync()直接返回的任务,代码工作得很好,但是如果我把它包装在一个async方法中,它就会被阻塞。

有人知道代码有什么问题吗?:(我可以更改为使用同步版本,但异步功能在其他自托管服务中可以找到…所以我想在这里使用相同的代码如果可能的话…

为什么等待从异步方法返回的任务会被阻塞

我在我的博客和最近的MSDN文章中描述了这种死锁行为。

要解决这个问题,您可以在任何地方使用ConfigureAwait(false),或者您可以使用同步方法。理想的解决方案是始终使用await而从不使用WaitResult,但这在您的情况下可能不可能(只有当Nancy使用async代表(即Get["/async/"] = async p => { ... };)时才会有效)。

除了Stephen提供的解决方案之外,我还解决了在Nancy路由处理程序的根中更改同步上下文的问题。给定这个实用函数:

using System;
using System.Threading;
namespace Utility.Async{
    static public class TPContext{
        static public T Call<T>(Func<T> handler) {
            var currentContext = SynchronizationContext.Current;
            SynchronizationContext.SetSynchronizationContext(null);
            try {
                return handler();
            }finally {
                SynchronizationContext.SetSynchronizationContext(currentContext);
            }
        } 
    }
}

用这个函数包装处理程序

        Get["/async/"] = p => TPContext.Call(() => {
            var req = WebRequest.CreateHttp("http://localhost:13254/");
            var responseTask = getResponse(req);
            var waitSuccess = responseTask.Wait(10000);
            return waitSuccess ? "Yeah!" : "woooh!";
        });

,它只是工作^^a我不认为我需要ASP。网络背景下. .实际上,我希望Nancy能够创建自己的同步上下文,因为Nancy在概念上已经与Asp.net不同了。