我的代码隐藏(aspx.cs)中有以下代码:
protected void button1_Click(object sender, EventArgs e)
{
new Thread(delegate() {
try
{
Thread.Sleep(30000); //do nothing for 30 seconds
}
catch (Exception ex)
{
//I AWLAYS get a ThreadAbortException here
//in about 1 second WHY!?!??!
}
}).Start();
}
请求结束时ASP.NET是否会终止所有子线程?
PS。我预测很多“因为这不是最佳实践”的答案。我知道在Windows服务中运行东西的最佳实践等。我只是好奇为什么正确线程在这个特定代码中被杀死,因为没有“Response.Redirect”,没有“响应” .End“,没有池循环,没有IIS重启等等(典型的原因是人们重复”ASP.NET中的后台线程是坏的“口头禅)。
更新:事实证明在ASP.NET MVC中工作正常!线程仅在Web表单中中止!哪个更奇怪。有什么想法吗?
答案 0 :(得分:17)
好的,所以经过48小时的实验,我发现了这些:
如果您使用MVC - 只需正常启动线程,它们将不会在当前请求结束后中止:
//MVC - works just fine
public ActionResult ThreadTest()
{
new Thread(delegate() {
try
{
System.Threading.Thread.Sleep(10000);
}
catch(Exception ex)
{
//no exception will be thrown
}
}).Start();
return Content("ok");
}
我了解到使用webforms你不能使用:
new Thread().Start(); //not working
ThreadPool.QueueUserWorkItem //not working
Action.BeginInvoke //not working
其他一些事情 - 都无法正常工作
以下是您需要做的事情:
1)在.aspx中将您的页面标记为“async”(这将告诉ASP.NET从IAsyncHandler继承该页面)
<%@ Page language="c#" Async="true" %>
2)在.aspx.cs中使用BackgroundWorker
protected void button1_Click(object sender, EventArgs e)
{
var bg = new BackgroundWorker();
bg.DoWork += delegate
{
try
{
Thread.Sleep(10000); //do nothing for 10 seconds
}
catch (Exception ex)
{
//no excpeiton is thrown
}
};
bg.RunWorkerAsync();
}
HostingEnvironment.QueueBackgroundWorkItem
“HostingEnvironment.QueueBackgroundWorkItem方法可以让你 安排小背景工作项目。 ASP.NET跟踪这些项目和 防止IIS突然终止工作进程,直到所有 后台工作项目已完成。无法调用此方法 在ASP.NET托管应用程序域之外。“
感谢@ danny-tuppeny最后一次
答案 1 :(得分:5)
响应的结束通常会杀死一个线程,是的。如果您调用Response.End
,您甚至可以看到IIS抛出ThreadAbortedException
以立即终止该线程。通常,您不应该在IIS中执行任何长时间运行的任务,尤其是在任务或后台线程上。有关为什么要避免这种情况的更多信息,以及如何强制IIS处理长时间运行的操作(如果你真的必须),请查看以下链接:
答案 2 :(得分:1)
提供另一种解决方案:不需要使用async
属性设置您的网页。以下代码可以正常工作:
new Thread
(
delegate()
{
try
{
MyMethod(myVar);
}
catch (Exception ex)
{
// handle
}
}
)
{
IsBackground = true
}.Start();
在此代码中,IsBackground = true
是阻止请求完成时中止线程的原因。
答案 3 :(得分:0)
如果没有请求访问aspx / asmx页面以保存IIS上的内存,ASP.NET工作进程将卸载虚拟应用程序。
IIS正在推出你的线程,因为它不是后台线程。
在IIS上有这个选项:
<processModel
enable="true"
timeout="Infinite"
idleTimeout="Infinite"
shutdownTimeout="0:00:05"
requestLimit="Infinite"
requestQueueLimit="5000"
restartQueueLimit="10"
memoryLimit="60"
webGarden="false"
cpuMask="0xffffffff"
userName="machine"
password="AutoGenerate"
logLevel="Errors"
clientConnectedCheck="0:00:05"
comAuthenticationLevel="Connect"
comImpersonationLevel="Impersonate"
responseRestartDeadlockInterval="00:09:00"
responseDeadlockInterval="00:03:00"
maxWorkerThreads="20"
maxIoThreads="20"
/>