C# - Альтернатива Системе. Таймеры. Таймер, для вызывания функции в определенное время

Я хочу вызвать определенную функцию на своем приложении C# в определенное время. Сначала я думал об использовании a Timer (System.Time.Timer), но это скоро стало невозможным использовать. Почему?

Простой. Класс Таймера требует a Interval в миллисекундах, но полагая, что я мог бы хотеть, чтобы функция была выполнена, позвольте нам, говорит за неделю, которая означала бы:

  • 7 дней = 168 часов;
  • 168 часов = 10 080 минут;
  • 10 080 минут = 604 800 секунд;
  • 604 800 секунд = 604 800 000 миллисекунд;
  • Таким образом, интервал был бы 604,800,000;

Теперь давайте помнить что Interval принятый тип данных int, и поскольку мы знаем int диапазон идет от-2 147 483 648 до 2,147,483,647.

Это делает Timer бесполезный, не в этом случае, но в случае больше, чем приблизительно 25 дней, после того как мы не можем установить a Interval больше это 2 147 483 647 миллисекунд.


Таким образом, мне нужно решение, где я мог указать, когда функция должна быть вызвана. Что-то вроде этого:

solution.ExecuteAt = "30-04-2010 15:10:00";
solution.Function = "functionName";
solution.Start();

Таким образом, когда Системное время достигло бы "30.04.2010, 15:10:00" функция будет выполняться в приложении.

Как эта проблема может быть решена?


Дополнительная информация: Что сделают эти функции?

  • Получение информации климата и на основе той информации:
  • Запуск / Закрытие других приложений (большинство из них базирующаяся консоль);
  • Отправка пользовательских команд к тем консольным приложениям;
  • Выключитесь, перезагрузка, сон, будьте в спящем режиме компьютер;
  • И если возможное расписание BIOS для включения компьютера;

Править:

Казалось бы что Interval принятый тип данных double, однако, если Вы устанавливаете значение, больше что int к Interval, и звоните Start() это выдает исключение [0, Int32.MaxValue].

РЕДАКТИРОВАНИЕ 2:

Jørn Schou-поехал на предложенном использовании Ncron для справлений с задачами планирования, и в первом взгляде это кажется хорошим решением, но я хотел бы услышать о некоторых, кто работал с ним.

19
задан PeeHaa 3 November 2013 в 17:45
поделиться

7 ответов

Один из подходов к планированию задач, аналогичный предложенному klausbyskov, заключается в создании службы планирования на основе существующей среды планирования .NET. /библиотека. По сравнению с использованием планировщика задач Windows, это имеет преимущества: (а) возможность определения нескольких заданий в одном проекте и (б) сохранение заданий и логики планирования «вместе», то есть отсутствие зависимости от настроек сервера, которые могут потеряться в модернизация / замена системы.

Я знаю два проекта с открытым исходным кодом, которые предлагают такую ​​функциональность:

  • « Quartz.NET - это полнофункциональная система планирования заданий с открытым исходным кодом, которую можно использовать от самых маленьких приложений до крупномасштабные корпоративные системы ". Я сам никогда не использовал этот фреймворк, но, изучив веб-сайт, у меня сложилось впечатление, что это очень надежный инструмент, предоставляющий множество интересных функций.Тот факт, что в Stackoverflow есть тег [quartz-net] , также может указывать на то, что он действительно используется в дикой природе.

  • « NCron - это облегченная библиотека для создания и развертывания запланированных фоновых заданий на платформе .NET-сервера». У него не вдвое меньше функций, чем у Quartz.NET, и у него нет тега в Stackoverflow, но автор (искренне ваш) считает, что его API с низким коэффициентом трения несколько упрощает начало работы.

Создавая службу планирования на базе NCron, вы можете запланировать еженедельное выполнение CleanupJob , используя одну строку кода:

service.Weekly().Run<CleanupJob>();

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

10
ответ дан 30 November 2019 в 03:24
поделиться

Вы можете использовать класс System.Threading.Timer , который предоставляет конструктор, принимающий интервал, выраженный как Int64, что должно быть достаточно для вашего потребности.

Теперь о другом:

  • Вы можете запускать / останавливать / настраивать программу, используя класс Process (я действительно не понимаю, что вы называете «пользовательскими командами»)
  • Вы не можете перезапустите или выключите или управляйте локальным BIOS с помощью собственных классов .NET. Перезагрузка / перезапуск возможен через Interop (вызов собственного Windows API из .NET), а планирование BIOS просто невозможно. А может со специальной материнской платой сервера? Я не знаю ..
0
ответ дан 30 November 2019 в 03:24
поделиться

Используйте System.Threading.Timer:

    var timer = new System.Threading.Timer(delegate { }, // Pass here a delegate to the method
        null,
        TimeSpan.FromDays(7), // Execute Method after 7 days.
        TimeSpan.Zero);
3
ответ дан 30 November 2019 в 03:24
поделиться

Ваш метод «Start ()» должен порождать поток, который просыпается с заданным интервалом, проверяет время, и если вы не достигли желаемого время, снова засыпает.

12
ответ дан 30 November 2019 в 03:24
поделиться

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

11
ответ дан 30 November 2019 в 03:24
поделиться

Класс System.Threading.Timer также имеет такое же ограничение (это вызовет исключение ArgumentOutOfRangeException согласно MSDN ).

Похоже, что не существует класса .Net Framework, способного обойти верхнюю границу Int32.MaxValue миллисекунд.

public static class Scheduler
{
    private const long TimerGranularity = 100;

    static Scheduler()
     {
         ScheduleTimer = new Timer(Callback, null, Timeout.Infinite, Timeout.Infinite);
        Tasks = new SortedQueue<Task>();
     }

    private static void Callback(object state)
    {
        var first = Tasks.Peek();
        if(first.ExecuteAt<DateTime.Now)
        {
            Tasks.Dequeue();
            var executionThread = new Thread(() => first.Function());
            executionThread.Start();                
        }
    }

    private static Timer ScheduleTimer { get; set; }

    public static void Start()
    {
        ScheduleTimer.Change(0, TimerGranularity);
    }
    public static void Add(Task task)
    {
        Tasks.Enqueue(task);
    }

    public static SortedQueue<Task> Tasks { get; set; }
}

public class Task : IComparable<Task>
{
    public Func<Boolean> Function { get; set; }

    public DateTime ExecuteAt { get; set; }

    public int CompareTo(Task other)
    {
        return ExecuteAt.CompareTo(other.ExecuteAt);
    }
}

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

Задачи добавляются в очередь, способную выполнять отсортированную вставку. Обратите внимание, что SortedQueue - это не тип .Net Framework, а гипотетическая, легко кодируемая коллекция, способная к отсортированной вставке на сопоставимый тип T.

Планировщик пробуждается каждые ] TimerGranularity миллисекунд и проверяет первую задачу, чье время «ExecuteAt» было превышено ; затем выполняет его в отдельном потоке.

Дополнительные усилия могут быть предприняты путем создания списка всех превзойденных задач (вместо только первого); но я оставил это для ясности.

0
ответ дан 30 November 2019 в 03:24
поделиться

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

  1. Определите разницу между DateTime.Now и желаемым временем.
  2. Если разница (в миллисекундах) превышает максимально допустимое значение для свойства Timer.Interval, установите для параметра Interval максимально допустимое значение (например, double.MaxValue или что-то еще) и запустите его.
  3. Теперь, когда таймер истечет в первый раз, вы просто вернетесь к шагу 1.

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

3
ответ дан 30 November 2019 в 03:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: