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

Ale*_*lex 12 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();
}
Run Code Online (Sandbox Code Playgroud)

ASP.NET会在请求结束时终止所有子线程吗?

PS.我预测很多"因为这不是最佳实践"的答案.我知道在Windows服务中运行东西的最佳实践等.我只是好奇为什么线程在这个特定的代码中被杀死,因为没有"Response.Redirect",没有"Response.End",没有池回收没有IIS重启等等(人们重复"ASP.NET中的后台线程是坏的"口头禅的典型原因).

更新:事实证明它在ASP.NET MVC中工作正常!线程仅在Web表单中中止!哪个更奇怪.有任何想法吗?

Ale*_*lex 18

好的,经过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");
}
Run Code Online (Sandbox Code Playgroud)

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" %>
Run Code Online (Sandbox Code Playgroud)

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();
}
Run Code Online (Sandbox Code Playgroud)

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

"HostingEnvironment.QueueBackgroundWorkItem方法允许您安排小的后台工作项.ASP.NET跟踪这些项目并阻止IIS突然终止工作进程,直到所有后台工作项都完成.此方法无法在ASP.NET托管之外调用应用域名."

感谢@ danny-tuppeny最后一个


cos*_*ost 5

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

堆栈溢出问题在IIS中长时间运行的作业

asp.net中后台任务的危险