Подтвердить что ты не робот

Как я могу поднимать событие каждый час (или конкретный временной интервал каждый час) в .NET?

Я работаю над маленьким искателем веб-страниц, который будет запускаться в системном трее и каждый час пополнять веб-сайт в час.

Каков наилучший способ заставить .NET поднять событие каждый час или какой-то другой интервал для выполнения какой-либо задачи. Например, я хочу запускать событие каждые 20 минут в зависимости от времени. Событие будет поднято по адресу:

00:20
00:40
01:00
01:20
01:40

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

Я бы использовал Timer, но я предпочел бы что-то, что следует за "расписанием", которое выполняется в час или что-то в этом направлении.

Без настройки моего приложения в планировщике задач Windows это возможно?

UPDATE:
Я добавляю свой алгоритм для вычисления временного интервала для таймера. Этот метод принимает параметр "minute", и это время, когда таймер должен запускать галочку. Например, если параметр "minute" равен 20, таймер будет отмечать интервалы в расписании выше.

int CalculateTimerInterval(int minute)
{
    if (minute <= 0)
        minute = 60;
    DateTime now = DateTime.Now;

    DateTime future = now.AddMinutes((minute - (now.Minute % minute))).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1);

    TimeSpan interval = future - now;

    return (int)interval.TotalMilliseconds;
}

Этот код используется следующим образом:

static System.Windows.Forms.Timer t;
const int CHECK_INTERVAL = 20;


static void Main()
{
    t = new System.Windows.Forms.Timer();
    t.Interval = CalculateTimerInterval(CHECK_INTERVAL);
    t.Tick += new EventHandler(t_Tick);
    t.Start();
}

static void t_Tick(object sender, EventArgs e)
{
    t.Interval = CalculateTimerInterval(CHECK_INTERVAL);
}
4b9b3361

Ответ 1

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

Это просто основная идея. В зависимости от того, насколько точно вы должны быть, вы можете сделать больше.

int minutes = DateTime.Now.Minute;
int adjust = 10 - (minutes % 10);
timer.Interval = adjust * 60 * 1000;  

Ответ 3

Ниже приведен пример облегченной системы, использующей синхронизацию потоков и асинхронный вызов.

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

    public Form1()
    {
        InitializeComponent();

        //some fake data, obviously you would have your own.
        DateTime someStart = DateTime.Now.AddMinutes(1);
        TimeSpan someInterval = TimeSpan.FromMinutes(2);

        //sample call
        StartTimer(someStart,someInterval,doSomething);
    }

    //just a fake function to call
    private bool doSomething()
    {
        DialogResult keepGoing = MessageBox.Show("Hey, I did something! Keep Going?","Something!",MessageBoxButtons.YesNo);
        return (keepGoing == DialogResult.Yes);
    }

    //The following is the actual guts.. and can be transplanted to an actual class.
    private delegate void voidFunc<P1,P2,P3>(P1 p1,P2 p2,P3 p3);
    public void StartTimer(DateTime startTime, TimeSpan interval, Func<bool> action)
    {
        voidFunc<DateTime,TimeSpan,Func<bool>> Timer = TimedThread;
        Timer.BeginInvoke(startTime,interval,action,null,null);
    }

    private void TimedThread(DateTime startTime, TimeSpan interval, Func<bool> action)
    {
        bool keepRunning = true;
        DateTime NextExecute = startTime;
        while(keepRunning)
        {
            if (DateTime.Now > NextExecute)
            {
                keepRunning = action.Invoke();
                NextExecute = NextExecute.Add(interval);
            }
            //could parameterize resolution.
            Thread.Sleep(1000);
        }            
    }

Ответ 4

System.Windows.Forms.Timer(или System.Timers.Timer)

но поскольку теперь вы говорите, что не хотите использовать таймеры, вы можете запустить легкий процесс ожидания в другом потоке (проверить время, спятить несколько секунд, снова проверить время...) или создать компонент, который повышает событие (с использованием процесса легкого ожидания) в определенные запланированные времена или интервалы

Ответ 5

Другой стратегией для этого было бы записать LAST TIME, что процесс был запущен, и определить, прошел ли ваш желаемый интервал с этого времени. В этой стратегии вы должны закодировать свое событие для запуска, если прошедшее время равно ИЛИ БОЛЬШЕ, чем желаемый интервал. Таким образом, вы можете обрабатывать экземпляры, где длительные интервалы (один раз в день, например) могут быть пропущены, если по какой-то причине компьютер должен был быть отключен.

Итак, например:

  • lastRunDateTime = 5/2/2009 в 8 вечера
  • Я хочу запустить мой процесс каждые 24 часа.
  • В событии таймера проверьте, прошло ли 24 часа или БОЛЕЕ прошло с момента последнего запуска процесса.
  • Если да, запустите процесс, обновите lastRunDateTime, добавив к нему желаемый интервал (24 часа в этом случае, но все, что вам нужно)

Очевидно, что для восстановления после того, как система опустилась, вам нужно будет хранить lastRunDateTime в файле или базе данных где-нибудь, чтобы программа могла забрать, где она остановилась при восстановлении.

Ответ 6

Моя цель - запускать импорт около 03:00 каждую ночь.

Здесь мой подход, используя System.Timers.Timer:

private Timer _timer;
private Int32 _hours = 0;
private Int32 _runAt = 3;

protected override void OnStart(string[] args)
{
    _hours = (24 - (DateTime.Now.Hour + 1)) + _runAt;
    _timer = new Timer();
    _timer.Interval = _hours * 60 * 60 * 1000;
    _timer.Elapsed += new ElapsedEventHandler(Tick);
    _timer.Start();
}

void Tick(object sender, ElapsedEventArgs e)
{
    if (_hours != 24)
    {
        _hours = 24;
        _timer.Interval = _hours * 60 * 60 * 1000;
    }

    RunImport();
}