THX*_*138 5 asp.net-mvc multithreading
在GET请求我运行(类似):
public ActionResult Index(void) {
webClient.DownloadStringComplete += onComplete;
webClient.DownloadStringAsync(...);
return null;
}
Run Code Online (Sandbox Code Playgroud)
我发现onComplete在Index()完成执行之后才会调用它.我可以看到,onComplete在与Index执行的线程不同的线程上调用它.
问题:为什么会发生这种情况?为什么webClient的异步线程显然被阻塞,直到请求处理线程完成?
有没有办法解决这个问题,而无需启动新线程ThreadPool(我试过这个,并且使用线程池确实按预期工作.如果从ThreadPool的线程调用DownloadStringAsync,webClient的回调也会按预期发生).
ASP.NET MVC 3.0,.NET 4.0,MS Cassini开发Web服务器(VS 2010)
编辑:这是一个完整的代码:
public class HomeController : Controller {
private static ManualResetEvent done;
public ActionResult Index() {
return Content(DownloadString() ? "success" : "failure");
}
private static bool DownloadString() {
try {
done = new ManualResetEvent(false);
var wc = new WebClient();
wc.DownloadStringCompleted += (sender, args) => {
// this breakpoint is not hit until after Index() returns.
// It is weird though, because response isn't returned to the client (browser) until this callback finishes.
// Note: This thread is different from one Index() was running on.
done.Set();
};
var uri = new Uri(@"http://us.battle.net/wow/en/character/blackrock/hunt/simple");
wc.DownloadStringAsync(uri);
var timedout = !done.WaitOne(3000);
if (timedout) {
wc.CancelAsync();
// if this would be .WaitOne() instead then deadlock occurs.
var timedout2 = !done.WaitOne(3000);
Console.WriteLine(timedout2);
return !timedout2;
}
return true;
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
}
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
我很好奇,所以我询问了Microsoft内部的ASP.NET讨论别名,并得到了Levi Broderick的回复:
ASP.NET在内部使用SynchronizationContext进行同步,并且一次只允许一个线程控制该锁.在您的特定示例中,运行HomeController :: DownloadString的线程持有锁,但它正在等待触发ManualResetEvent.在DownloadStringCompleted方法运行之前,不会触发ManualResetEvent,但该方法在不能进行同步锁定的其他线程上运行,因为第一个线程仍然保留它.你现在陷入僵局.
我很惊讶这在MVC 2中曾经有效,但是如果它确实如此,那只是出乎意料的事故.这从未得到支持.
| 归档时间: |
|
| 查看次数: |
2474 次 |
| 最近记录: |