2

可能重复:
在c#中延迟任务启动的正确方法是什么

我需要安排将来执行的小任务(延迟总是<1分钟)。在 .NET 4.0 运行时上的 .NET 中实现。异步 ctp 是一个选项,尽管我暂时看不到附加值。

  • 调度需要是异步的
  • 调度分辨率以秒为单位
  • 任务执行是隐式异步的(我认为)
  • 计划任务的数量可能在数百甚至数千
  • 有可能,但不太可能,两个任务将被安排在完全相同的时间

我目前的解决方案是这样的:

internal class TimerState
{
    internal Timer Timer { get; set; }
    internal object Payload { get; set; }
    internal Action<object> Action { get; set; }
}

public class TimerModule
{
    public static void ScheduleTask(object input, Action<object> action, TimeSpan delay)
    {
        //create state to pass to timer method
        var state = new TimerState { Payload = input, Action = action };

        //schedule timer without firing 
        var t = new Timer(HandleScheduleTimer, state, -1, -1);

        //add timer to state to be able to dispose it
        state.Timer = t;

        //schedule timer to fire in delay time
        t.Change(delay, TimeSpan.FromMilliseconds(-1));
    }


    private static void HandleScheduleTimer(object state)
    {
        var s = state as TimerState;

        Task.Factory.StartNew(s.Action, s.Payload, CancellationToken.None,
                              TaskCreationOptions.PreferFairness, TaskScheduler.Current);

        //dispose the timer immediately
        if(s.Timer != null)
            s.Timer.Dispose();
    }
}

我已经使用性能计数器(.NET 物理线程)进行了一些测试,但我看不到有多少线程同时运行,即使我几乎同时安排了数千个任务。

有一个更好的方法吗?

是否有任何经过验证的设计模式?

大多数情况下,我发现调度在重新启动时是可靠的,但我不需要,我可以在崩溃后重播系统中的数据并补偿未执行的计划任务。

编辑:我并不是说我看到成千上万的线程同时运行。我知道这可能会由线程池处理。就像我在评论中说的那样,一个跨越 100 秒的 500 万个任务的测试只看到物理线程增加了 20 个。

我的主要问题是:有没有更好的方法来延迟任务执行?

4

1 回答 1

1

您正在寻找的解决方案是 Quartz。

http://quartznet.sourceforge.net/

它是一个非常强大的调度器,能够处理与不同调度相关的不同作业。它比计时器可靠得多。如果出现任何问题,它具有故障转移功能。

这些计划要么使用 CRON 间隔,要么可以在特定日期运行。我听说过有数千个工作的实例。如果需要,Quartz 可以集群化,并且可以运行有状态(保持先前实例的知识)和无状态作业。根据它们的配置方式,它们可以同时运行或在队列中运行。大多数线程和线程安全问题都已为您解决,您可以自由地编写作业类而不会感到头疼。

设置很简单(安装服务和配置),创建石英作业更加简单。创建一个继承自 IJob 的类,应用您的逻辑,并将其添加到石英配置中。Config 可以是 xml 文件、sql server 数据库,也可以创建自己的解决方案。我正在为 RavenDB 开发一个。

于 2012-06-08T12:40:50.620 回答