我应该如何在ASP.NET 4中执行长时间运行的任务?

时间:2021-09-16 05:18:30

I am building a website using .NET 4. There are lots of MSDN articles dating from 2003, about using Thread objects and 2007, using Asynchronous Pages in .NET 2, but that is all pretty stale. I know .NET 4 brought us the Task class and some people vaguely cautioning against its use for this purpose.

我正在使用.NET 4构建一个网站。有很多MSDN文章可追溯到2003年,关于使用Thread对象和2007,使用.NET 2中的异步页面,但这都非常陈旧。我知道.NET 4给我们带来了Task类,有些人模糊地警告不要将它用于此目的。

So I ask you, what is the "preferred" method circa 2011 for running background/asynchronous work under IIS in ASP.NET 4? What caveats are there about using Thread/Task directly? Is Async=true still in vogue?

所以我问你,大约2011年在ASP.NET 4中运行IIS下的后台/异步工作的“首选”方法是什么?关于直接使用Thread / Task有什么警告? Async = true还在流行吗?

EDIT: Ok, ok, from the answers it's clear the opinion is that I should make a service if I can. But the advantages to doing it inside the webapp are significant, especially easier deployment/redeployment. Assuming the process is safe-to-crash, then, if I were to do it inside IIS, what is the best way?

编辑:好的,好的,从答案很清楚,我认为如果可以,我应该提供服务。但在webapp中执行此操作的优势非常明显,尤其是更容易部署/重新部署。假设这个过程是安全崩溃的,那么,如果我在IIS中做这个,那么最好的方法是什么?

5 个解决方案

#1


16  

Preferentially, avoid having long tasks executing in such an environment.

优选地,避免在这样的环境中执行长任务。

Delegate long running tasks out to a stable system service via interoperability, leaving the web application responsive and only required for direct user requests.

通过互操作性将长时间运行的任务委派给稳定的系统服务,使Web应用程序保持响应,并且仅对直接用户请求提出要求。

Web applications have never been (and still aren't) considered reliable systems - anyone who has ever used a browser has encountered (at least) a time-out, to be sure; and such inconvenience (for both parties) is not limited to this scenario. Of course, any system can crash, but the circumstances surrounding such an event on a system built-to-be-persistent ought to completely exceptional.

Web应用程序从来没有(现在仍然没有)被认为是可靠的系统 - 任何使用过浏览器的人都会遇到(至少)超时的问题;这种不便(对双方而言)不仅限于这种情况。当然,任何系统都可能崩溃,但是在一个系统内置这种事件的情况应该是完全特殊的。

Windows services are designed to be long running, and if something goes wrong you've generally got more to worry about than your individual service.

Windows服务旨在长期运行,如果出现问题,您通常会比您的个人服务更担心。

#2


2  

It's best to be avoided, but if you are forced to, consider Hanselman's thoughts at How to run Background Tasks in ASP.NET.

最好避免使用,但如果你*,请考虑Hanselman关于如何在ASP.NET中运行后台任务的想法。

Among them, and for something quick and easy, I would suggest you look in particular at the QueueBackgroundWorkItem added in 4.5.2.

其中,为了快速简便,我建议你特别注意4.5.2中添加的QueueBackgroundWorkItem。

From personal experience, Task does not cut it. QueueBackgroundWorkItem is much better.

从个人经验来看,Task并没有削减它。 QueueBackgroundWorkItem要好得多。

#3


0  

You can create a static ThreadPool like this http://www.dotnetperls.com/threadpool with limited threads number(for example only 2). and then queue tasks in it, but it's highly not recommended because web servers are not for such kind of tasks

您可以使用有限的线程编号创建一个静态ThreadPool,例如http://www.dotnetperls.com/threadpool(例如,仅限2)。然后将任务排入其中,但强烈建议不要这样做,因为Web服务器不适用于此类任务

#4


0  

My preferred method is the same as Robert Harvey proposes in his answer.

我的首选方法与Robert Harvey在他的回答中提出的方法相同。

You can still use the Task Parallel Library, but spin the task up in a separate process outside of IIS (the reason being that IIS has a limited number of worker threads to hand out and imposes other limitations that can make long running tasks unpredictable).

您仍然可以使用任务并行库,但是在IIS之外的单独进程中启动任务(原因是IIS具有有限数量的工作线程以进行分发并施加其他限制,这可能使长时间运行的任务变得不可预测)。

#5


0  

This is a description of a 'once a day' scenario.

这是对“每天一次”情景的描述。

If you really want to avoid creating a service, you could start a timer with 1 minute intervals. Each time the timer delegate is invoked, you will have to run something like this (pseudo code):

如果您真的想避免创建服务,可以每隔1分钟启动一个计时器。每次调用计时器委托时,您都必须运行这样的程序(伪代码):

lastInvokeDay = LoadLastInvokeDate();
If (lastInvokeDay < DateTime.Now.Date && timeOfDayToRun == DateTime.Now.Time)
{
  try
  {
    today = DateTime.Now.Date;
    runMyTask();
  }
  catch..
  finally
  {
    lastInvokeDay = today;
    SaveLastInvokeDay(lastInvokeDay);
  }
}

Keep in mind that the lastInvokeDay should be persisted either in Database or on a file...

请记住,lastInvokeDay应该保存在数据库或文件中......

Now, If you want to enable immediate invocation of the task, you could simply call runMyTask() on demand. If its important for you to keep the runMyTask from occuring more than once a day, you could create a syncronized block of code inside it (with a lock statement) and move the lastInvokeDay check inside.

现在,如果要立即调用任务,可以根据需要调用runMyTask()。如果对于让每天多次运行runMyTask非常重要,可以在其中创建一个同步的代码块(使用lock语句)并在其中移动lastInvokeDay检查。

Does this answer your question?

这回答了你的问题了吗?

#1


16  

Preferentially, avoid having long tasks executing in such an environment.

优选地,避免在这样的环境中执行长任务。

Delegate long running tasks out to a stable system service via interoperability, leaving the web application responsive and only required for direct user requests.

通过互操作性将长时间运行的任务委派给稳定的系统服务,使Web应用程序保持响应,并且仅对直接用户请求提出要求。

Web applications have never been (and still aren't) considered reliable systems - anyone who has ever used a browser has encountered (at least) a time-out, to be sure; and such inconvenience (for both parties) is not limited to this scenario. Of course, any system can crash, but the circumstances surrounding such an event on a system built-to-be-persistent ought to completely exceptional.

Web应用程序从来没有(现在仍然没有)被认为是可靠的系统 - 任何使用过浏览器的人都会遇到(至少)超时的问题;这种不便(对双方而言)不仅限于这种情况。当然,任何系统都可能崩溃,但是在一个系统内置这种事件的情况应该是完全特殊的。

Windows services are designed to be long running, and if something goes wrong you've generally got more to worry about than your individual service.

Windows服务旨在长期运行,如果出现问题,您通常会比您的个人服务更担心。

#2


2  

It's best to be avoided, but if you are forced to, consider Hanselman's thoughts at How to run Background Tasks in ASP.NET.

最好避免使用,但如果你*,请考虑Hanselman关于如何在ASP.NET中运行后台任务的想法。

Among them, and for something quick and easy, I would suggest you look in particular at the QueueBackgroundWorkItem added in 4.5.2.

其中,为了快速简便,我建议你特别注意4.5.2中添加的QueueBackgroundWorkItem。

From personal experience, Task does not cut it. QueueBackgroundWorkItem is much better.

从个人经验来看,Task并没有削减它。 QueueBackgroundWorkItem要好得多。

#3


0  

You can create a static ThreadPool like this http://www.dotnetperls.com/threadpool with limited threads number(for example only 2). and then queue tasks in it, but it's highly not recommended because web servers are not for such kind of tasks

您可以使用有限的线程编号创建一个静态ThreadPool,例如http://www.dotnetperls.com/threadpool(例如,仅限2)。然后将任务排入其中,但强烈建议不要这样做,因为Web服务器不适用于此类任务

#4


0  

My preferred method is the same as Robert Harvey proposes in his answer.

我的首选方法与Robert Harvey在他的回答中提出的方法相同。

You can still use the Task Parallel Library, but spin the task up in a separate process outside of IIS (the reason being that IIS has a limited number of worker threads to hand out and imposes other limitations that can make long running tasks unpredictable).

您仍然可以使用任务并行库,但是在IIS之外的单独进程中启动任务(原因是IIS具有有限数量的工作线程以进行分发并施加其他限制,这可能使长时间运行的任务变得不可预测)。

#5


0  

This is a description of a 'once a day' scenario.

这是对“每天一次”情景的描述。

If you really want to avoid creating a service, you could start a timer with 1 minute intervals. Each time the timer delegate is invoked, you will have to run something like this (pseudo code):

如果您真的想避免创建服务,可以每隔1分钟启动一个计时器。每次调用计时器委托时,您都必须运行这样的程序(伪代码):

lastInvokeDay = LoadLastInvokeDate();
If (lastInvokeDay < DateTime.Now.Date && timeOfDayToRun == DateTime.Now.Time)
{
  try
  {
    today = DateTime.Now.Date;
    runMyTask();
  }
  catch..
  finally
  {
    lastInvokeDay = today;
    SaveLastInvokeDay(lastInvokeDay);
  }
}

Keep in mind that the lastInvokeDay should be persisted either in Database or on a file...

请记住,lastInvokeDay应该保存在数据库或文件中......

Now, If you want to enable immediate invocation of the task, you could simply call runMyTask() on demand. If its important for you to keep the runMyTask from occuring more than once a day, you could create a syncronized block of code inside it (with a lock statement) and move the lastInvokeDay check inside.

现在,如果要立即调用任务,可以根据需要调用runMyTask()。如果对于让每天多次运行runMyTask非常重要,可以在其中创建一个同步的代码块(使用lock语句)并在其中移动lastInvokeDay检查。

Does this answer your question?

这回答了你的问题了吗?