【问题标题】:WebClient Deadlocking in ASP.NET MVC (Synchronous Action Method)ASP.NET MVC 中的 WebClient 死锁(同步动作方法)
【发布时间】:2012-06-29 21:47:37
【问题描述】:
public class HomeController : Controller
{
    public ActionResult Index()
    {
        Task<string> t = DownloadStringTaskAsync(new Uri("http://www.google.com/search?q=aspnet"));
        t.Wait();
        string res = t.Result;

        return View((object)res);
    }

    Task<string> DownloadStringTaskAsync(Uri address)
    {
        TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
        WebClient wc = new WebClient();
        wc.DownloadStringCompleted += (s, e) => tcs.SetResult(e.Result);
        wc.DownloadStringAsync(address);
        return tcs.Task;
    }
}

操作永远不会返回,请求只会超时。

我们将 TPL 任务用​​于所有异步操作,并且在切换到框架 4.5 之前必须包装一些 WebClient 的方法。

上述方法DownloadStringTaskAsync 是其中一个包装器的简化版本。

我想不通的是,为什么等待任务会使 aspnet 中的线程死锁,并且在控制台或桌面应用程序中工作正常。

这是死锁线程的样子。

请求线程

[处于睡眠、等待或加入]
mscorlib.dll!System.Threading.Monitor.Wait(object obj, int millisecondsTimeout, bool exitContext) + 0x18 字节 mscorlib.dll!System.Threading.ManualResetEventSlim.Wait(int millisecondsTimeout, System.Threading.CancellationToken cancelToken) + 0x264 字节
mscorlib.dll!System.Threading.Tasks.Task.InternalWait(int millisecondsTimeout, System.Threading.CancellationToken cancelToken) + 0x166 字节 mscorlib.dll!System.Threading.Tasks.Task.Wait(int millisecondsTimeout, System.Threading.CancellationToken cancelToken) + 0x41 字节
mscorlib.dll!System.Threading.Tasks.Task.Wait() + 0xb 字节
TCSProblem.DLL!TCSProblem.Controllers.HomeController.Index() 第 16 行 + 0xa 字节

WebClient 线程

[处于睡眠、等待或加入]
mscorlib.dll!System.Threading.Monitor.Enter(object obj, ref bool lockTaken) + 0x14 字节
System.Web.dll!System.Web.AspNetSynchronizationContext.CallCallback(System.Threading.SendOrPostCallback 回调,对象状态) + 0x53 字节
System.Web.dll!System.Web.AspNetSynchronizationContext.Post(System.Threading.SendOrPostCallback 回调,对象状态) + 0x9 字节
System.dll!System.ComponentModel.AsyncOperation.Post(System.Threading.SendOrPostCallback d, object arg) + 0x29 字节
System.dll!System.Net.WebClient.PostProgressChanged(System.ComponentModel.AsyncOperation asyncOp, System.Net.WebClient.ProgressData 进度) + 0x25c 字节

【问题讨论】:

  • 您使用异步下载无济于事,反而有害。我猜这段代码取自更大的代码示例?
  • FWIW,如您所写,您可以删除 't.Wait();'因为访问 Result 属性将阻塞,直到任务完成。

标签: c# asp.net-mvc asynchronous task-parallel-library


【解决方案1】:

所有 .NET 类默认捕获 SynchronizationContext,我遇到了类似的问题:SmtpClient.SendAsync blocking my ASP.NET MVC Request

【讨论】:

    【解决方案2】:

    不幸的是,WebClient 捕获了当前的同步上下文并通过发布到它来引发完成事件。因此,完成操作仅在您从您的操作方法返回后运行,这永远不会发生。这意味着,你要么......

    1. ...需要将您对 DownloadStringAsync 的调用包装在 Task.Factory.StartNew 中,以便切换到没有同步上下文的线程
    2. ...调用前需要将SynchronizationContext.Current设置为null,之后再恢复
    3. ...使用异步 MVC 操作

    【讨论】:

    • 谢谢!我最终使用了第一种方法,2 似乎太麻烦了,3 在我的情况下不是一个选择。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-14
    • 1970-01-01
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多