为什么ASP.NET杀死我的后台线程?

时间:2014-05-05 22:39:13

标签: c# asp.net multithreading

我的代码隐藏(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表单中中止!哪个更奇怪。有什么想法吗?

4 个答案:

答案 0 :(得分:17)

好的,所以经过48小时的实验,我发现了这些:

1。可以在ASP.NET _MVC _

中运行后台线程

如果您使用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");
}

2。对于Web表单 - 将BackgroundWorker与“Async”页面属性

结合使用

我了解到使用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();
}

3。如果您使用的是.NET 4.5.2或更高版本 - 只需使用HostingEnvironment.QueueBackgroundWorkItem

即可
  

“HostingEnvironment.QueueBackgroundWorkItem方法可以让你   安排小背景工作项目。 ASP.NET跟踪这些项目和   防止IIS突然终止工作进程,直到所有   后台工作项目已完成。无法调用此方法   在ASP.NET托管应用程序域之外。“

感谢@ danny-tuppeny最后一次

答案 1 :(得分:5)

响应的结束通常会杀死一个线程,是的。如果您调用Response.End,您甚至可以看到IIS抛出ThreadAbortedException以立即终止该线程。通常,您不应该在IIS中执行任何长时间运行的任务,尤其是在任务或后台线程上。有关为什么要避免这种情况的更多信息,以及如何强制IIS处理长时间运行的操作(如果你真的必须),请查看以下链接:

Stack Overflow Question on long running jobs in IIS

The dangers of background tasks in asp.net

答案 2 :(得分:1)

ASP.NET WebForms

提供另一种解决方案:需要使用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"
/>