C# ASP.NET MVC(同步操作方法)中的WebClient死锁 公共类HomeController:控制器 { 公共行动结果索引() { Task t=DownloadStringTaskAsync(新Uri(“http://www.google.com/search?q=aspnet")); t、 等待(); 字符串res=t.结果; 返回视图((对象)res); } 任务下载StringTaskAsync(Uri地址) { TaskCompletionSource tcs=新的TaskCompletionSource(); WebClient wc=新的WebClient(); wc.DownloadStringCompleted+=(s,e)=>tcs.SetResult(e.Result); wc.DownloadStringAsync(地址); 返回tcs.Task; } }
操作将永远不会返回,请求将只是超时 我们对所有异步操作都使用TPL任务,在切换到Framework4.5之前,我们必须包装WebClient的一些方法 上述方法C# ASP.NET MVC(同步操作方法)中的WebClient死锁 公共类HomeController:控制器 { 公共行动结果索引() { Task t=DownloadStringTaskAsync(新Uri(“http://www.google.com/search?q=aspnet")); t、 等待(); 字符串res=t.结果; 返回视图((对象)res); } 任务下载StringTaskAsync(Uri地址) { TaskCompletionSource tcs=新的TaskCompletionSource(); WebClient wc=新的WebClient(); wc.DownloadStringCompleted+=(s,e)=>tcs.SetResult(e.Result); wc.DownloadStringAsync(地址); 返回tcs.Task; } },c#,asp.net-mvc,asynchronous,task-parallel-library,C#,Asp.net Mvc,Asynchronous,Task Parallel Library,操作将永远不会返回,请求将只是超时 我们对所有异步操作都使用TPL任务,在切换到Framework4.5之前,我们必须包装WebClient的一些方法 上述方法downloadstringtaskancy是其中一个包装器的简化版本 我不明白的是,为什么等待任务会使aspnet中的线程死锁,并在控制台或桌面应用程序中正常工作 下面是死锁线程的样子 请求线程 [处于睡眠、等待或加入状态] mscorlib.dll!System.Threading.Monitor.Wait(对象obj,int毫秒计时
downloadstringtaskancy
是其中一个包装器的简化版本
我不明白的是,为什么等待任务会使aspnet中的线程死锁,并在控制台或桌面应用程序中正常工作
下面是死锁线程的样子
请求线程
[处于睡眠、等待或加入状态]mscorlib.dll!System.Threading.Monitor.Wait(对象obj,int毫秒计时,bool exitContext)+0x18字节 mscorlib.dll!System.Threading.ManualResetEventSlim.Wait(int毫秒计时,System.Threading.CancellationToken CancellationToken)+0x264字节
mscorlib.dll!System.Threading.Tasks.Task.InternalWait(int毫秒计时,System.Threading.CancellationToken CancellationToken)+0x166字节 mscorlib.dll!System.Threading.Tasks.Task.Wait(int毫秒计时,System.Threading.CancellationToken CancellationToken)+0x41字节
mscorlib.dll!System.Threading.Tasks.Task.Wait()+0xb字节
TCSProblem.DLL!TCSProblem.Controllers.HomeController.Index()行16+0xa字节 网络客户端线程 [处于睡眠、等待或加入状态]
mscorlib.dll!System.Threading.Monitor.Enter(对象对象对象,参考布尔锁定)+0x14字节
System.Web.dll!System.Web.AspNetSynchronizationContext.CallCallCallback(System.Threading.SendOrPostCallback回调,对象状态)+0x53字节
System.Web.dll!System.Web.AspNetSynchronizationContext.Post(System.Threading.SendOrPostCallback,对象状态)+0x9字节
System.dll!System.ComponentModel.AsyncOperation.Post(System.Threading.SendOrPostCallback,对象arg)+0x29字节
System.dll!System.Net.WebClient.PostProgressChanged(System.ComponentModel.AsyncOperation asyncOp,System.Net.WebClient.ProgressData progress)+0x25c字节
不幸的是,WebClient捕获了当前的同步上下文,并通过向其中发布来引发完成事件。正因为如此,完成操作只能在您从操作方法返回后运行,这是永远不会发生的。这意味着,你要么
默认情况下,所有.NET类都会捕获SynchronizationContext,我遇到了类似的问题:谢谢!我最终使用了第一种方法,2看起来太匆忙了,而3在我的情况下不是一个选项。你使用异步下载没有帮助,但有伤害。我猜这段代码是从一个更大的代码示例?FWIW中提取的,正如所写的,您可以删除't.Wait();'因为访问结果属性将被阻止,直到任务完成。
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;
}
}