我应该在System.Timers.Timer中使用线程池,线程或后台工作程序吗?

时间:2012-06-22 08:24:19

标签: .net multithreading backgroundworker threadpool task-parallel-library

public class JobRunner
{
    internal Timer Timer;
    internal readonly IEnumerable<YuartzJob> Jobs;

    public void Start()
    {
        this.Timer = new Timer(5000);
        this.Timer.Elapsed += Timer_Elapsed;
        this.Timer.Start();
    }

    public void Stop()
    {
        this.Timer.Stop();
    }

    internal void Timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        foreach (var job in Jobs)
        {
            MyActivator.RunJob(job);
        }
    }
}

public class MyActivator
{
    public static void RunJob(YuartzJob job)
    {
        var objectHandle = Activator.CreateInstance(job.AssemblyName, job.ClassName).Unwrap();
        var currentJob = (IJob)objectHandle;
        currentJob.Run();
    }
}

我应该如何使用MyActivator.RunJob(作业):

  1. 我应该使用ThreadPool调用MyActivator.RunJob吗?
  2. 我应该使用Threads调用MyActivator.RunJob吗?
  3. 我应该使用BackgroundWorker调用MyActivator.RunJob吗?
  4. 没有做任何事情会这样吗?

3 个答案:

答案 0 :(得分:3)

如果您的目标是.NET 4,最简单的方法是使用任务。任务使用ThreadPool中的线程执行方法。 .NET运行时(实际上是一个TaskScheduler)确保线程池不会被太多任务耗尽:

    foreach (var job in Jobs)
    {
        Task.Factory.StartNew(()=>MyActivator.RunJob(job));
    }

任务还允许轻松取消,异常处理和链接,这在使用ThreadPool或您自己的线程时是不可能的。

对于早期版本,您应首先考虑ThreadPool,并且只创建自己的线程,如果作业太长且运行时间很长,以至于它们可能会耗尽线程池:

    foreach (var job in Jobs)
    {
        ThreadPool.QueueUserWorkItem(o=>MyActivator.RunJob(job));
    }

后台工作程序在.NET 4+中被认为是过时的,并且仅适用于非常粗粒度的并行性。在您的情况下,您必须为每个作业创建一个单独的工作程序,订阅它的事件,运行它并在它之后进行清理。

答案 1 :(得分:2)

如果您想要有效地并行处理项目集合,我的第一选择就是为此目的而做的事情:Parallel.ForEach()

在内部,它使用Task s,这意味着它将在ThreadPool上运行。它还会尝试有效地使用Task,所以如果你有一百万个项目的集合,它就不会创建一百万个Task

答案 2 :(得分:-1)

.NET Framework提供了四个计时器。其中两个是通用多线程定时器:

  • System.Threading.Timer
  • System.Timers.Timer

另外两个是特殊用途的单线程定时器:

  • System.Windows.Forms.Timer(Windows窗体计时器)
  • System.Windows.Threading.DispatcherTimer(WPF计时器)

因此,如果您希望以多线程方式/并行方式执行您的方法,那么您必须选择前两个方法。

详细了解此问题以及示例源代码here