【问题标题】:Why waiting a task returned from async method gets blocked?为什么等待从异步方法返回的任务被阻塞?
【发布时间】:2013-06-04 19:16:29
【问题描述】:

我正在开发一个 Nancy/ASP.Net 项目。我尝试使用 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.Net 页面上。 localhost:13254 上的服务运行良好。如果我使用从请求的 GetResponseAsync() 直接返回的任务,代码可以正常工作,但如果我将它包装在异步方法中,它就会被阻塞。

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

【问题讨论】:

    标签: c# asynchronous async-await nancy


    【解决方案1】:

    我描述了这种死锁行为on my blogin a recent MSDN article

    要解决此问题,您可以在任何地方使用ConfigureAwait(false),也可以使用同步方法。 理想的解决方案是一直使用await,永远不要使用WaitResult,但这在您的情况下可能是不可能的(只有在南希与@987654327合作时才有效@代表,即Get["/async/"] = async p =&gt; { ... };)。

    【讨论】:

    • 感谢您指出这一点:D 我还没有尝试过 Nancy Async,所以我不得不忍受一段时间。
    【解决方案2】:

    除了 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.Net 上下文..实际上我希望 Nancy 会创建自己的同步上下文,因为 Nancy 在概念上与 Asp.net 的工作方式已经不同了。

    【讨论】:

      猜你喜欢
      • 2023-03-22
      • 1970-01-01
      • 2019-10-16
      • 2018-09-03
      • 1970-01-01
      • 1970-01-01
      • 2014-10-01
      • 2017-11-11
      相关资源
      最近更新 更多