Расписание звонков делегатов - PullRequest
1 голос
/ 01 февраля 2009

Я хочу иметь возможность планировать обратные вызовы, я хочу иметь возможность регистрировать множество различных обратных вызовов в разное время для объекта «Планировщик». Как то так.

public class Foo
{
    public void Bar()
    {
        Scheduler s = new Scheduler();
        s.Schedule(() => Debug.WriteLine("Hello in an hour!"), DateTime.Now.AddHours(1));
        s.Schedule(() => Debug.WriteLine("Hello a week later!"), DateTime.Now.AddDays(7));
    }
}

Лучший способ, которым я могу придумать для реализации Планировщика, - это запустить таймер внутри с заданным интервалом, и каждый раз, когда интервал истекает, я проверяю зарегистрированные обратные вызовы и проверяю, пора ли их вызвать, если да делать. Это довольно просто, но имеет тот недостаток, что вы получаете только «разрешение» таймера. Допустим, таймер установлен на тик один раз в секунду, и вы регистрируете обратный вызов, который будет вызываться через полсекунды, но он все равно может не вызываться целую секунду.

Есть ли лучший способ решить эту проблему?

Ответы [ 5 ]

2 голосов
/ 01 февраля 2009

Это хороший подход. Вы должны динамически настроить таймер на отключение, как только произойдет следующее событие. Вы делаете это, помещая задания в приоритетную очередь. В конце концов, в любом случае вы всегда ограничены разрешением , которое может предоставить система, но вам следует кодировать так, чтобы это был only ограничивающий фактор.

1 голос
/ 01 февраля 2009

Вам действительно нужен планировщик только для того, чтобы проснуться и выполнить что-либо, когда должен появиться самый ранний элемент в списке. После этого вы устанавливаете таймер для следующего запуска планировщика.

Когда добавляется новый элемент, вы просто сравниваете его расписание с текущим ожидаемым. Если раньше, вы отменяете текущий таймер и устанавливаете новый элемент в качестве следующего запланированного элемента.

1 голос
/ 01 февраля 2009

Хороший способ сделать это - изменить продолжительность вашего таймера: попросите его сработать, когда (но не раньше) наступит ваше первое / следующее запланированное событие.

< Стандартный отказ от ответственности за то, что Windows не является операционной системой реального времени, поэтому ее таймеры всегда должны быть немного неточными >

0 голосов
/ 07 декабря 2010

Quartz.Net планировщик заданий. Тем не менее, это расписание классов, а не делегатов.

0 голосов
/ 01 февраля 2009

Вот класс, который я написал для этого, используя встроенный в .NET класс Timer.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Sample
{
    /// <summary>
    /// Use to run a cron job on a timer
    /// </summary>
    public class CronJob
    {
        private VoidHandler cronJobDelegate;
        private DateTime? start;
        private TimeSpan startTimeSpan;
        private TimeSpan Interval { get; set; }

        private Timer timer;

        /// <summary>
        /// Constructor for a cron job
        /// </summary>
        /// <param name="cronJobDelegate">The delegate that will perform the task</param>
        /// <param name="start">When the cron job will start. If null, defaults to now</param>
        /// <param name="interval">How long between each execution of the task</param>
        public CronJob(VoidHandler cronJobDelegate, DateTime? start, TimeSpan interval)
        {
            if (cronJobDelegate == null)
            {
                throw new ArgumentNullException("Cron job delegate cannot be null");
            }

            this.cronJobDelegate = cronJobDelegate;
            this.Interval = interval;

            this.start = start;
            this.startTimeSpan = DateTime.Now.Subtract(this.start ?? DateTime.Now);

            this.timer = new Timer(TimerElapsed, this, Timeout.Infinite, Timeout.Infinite);
        }

        /// <summary>
        /// Start the cron job
        /// </summary>
        public void Start()
        {
            this.timer.Change(this.startTimeSpan, this.Interval);
        }

        /// <summary>
        /// Stop the cron job
        /// </summary>
        public void Stop()
        {
            this.timer.Change(Timeout.Infinite, Timeout.Infinite);
        }

        protected static void TimerElapsed(object state)
        {
            CronJob cronJob = (CronJob) state;
            cronJob.cronJobDelegate.Invoke();
        }
    }
}
...