Как бы вы изменили мой процесс Heartbeat, написанный на C #? - PullRequest
8 голосов
/ 27 января 2010

Я смотрю на реализацию процесса «Heartbeat» для выполнения множества повторяющихся задач очистки в течение дня.

Это хороший шанс использовать шаблон Command, поэтому у меня есть интерфейс, который выглядит следующим образом:

   public interface ICommand
   {
       void Execute();
       bool IsReady();
   }

Затем я создал несколько задач, которые хочу запустить. Вот базовый пример:

public class ProcessFilesCommand : ICommand
{
    private int secondsDelay;
    private DateTime? lastRunTime;

    public ProcessFilesCommand(int secondsDelay)
    {
        this.secondsDelay = secondsDelay;
    }

    public void Execute()
    {
        Console.WriteLine("Processing Pending Files...");
        Thread.Sleep(5000); // Simulate long running task
        lastRunTime = DateTime.Now;
    }

    public bool IsReady()
    {
        if (lastRunTime == null) return true;

        TimeSpan timeSinceLastRun = DateTime.Now.Subtract(lastRunTime.Value);
        return (timeSinceLastRun.TotalSeconds > secondsDelay);
    }

}

Наконец, мое консольное приложение запускается в этом цикле в поисках ожидающих задач для добавления в ThreadPool:

class Program
{
    static void Main(string[] args)
    {

        bool running = true;

        Queue<ICommand> taskList = new Queue<ICommand>();
        taskList.Enqueue(new ProcessFilesCommand(60)); // 1 minute interval
        taskList.Enqueue(new DeleteOrphanedFilesCommand(300)); // 5 minute interval

        while (running)
        {
            ICommand currentTask = taskList.Dequeue();
            if (currentTask.IsReady())
            {
                ThreadPool.QueueUserWorkItem(t => currentTask.Execute());
            }
            taskList.Enqueue(currentTask);
            Thread.Sleep(100);
        }

    }
}

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

Похоже ли это на "ОК" дизайн для того, что я хочу сделать? Есть ли что-нибудь, что вы бы изменили?

Ответы [ 5 ]

10 голосов
/ 27 января 2010

Это отличное начало. Недавно мы сделали несколько таких вещей, поэтому я могу предложить несколько предложений.

  1. Не использовать пул потоков для длительных задач. Пул потоков предназначен для выполнения множества маленьких задач. Если вы выполняете долго выполняемые задачи, используйте отдельный поток. Если вы истощаете пул потоков (используете все задачи), все, что попадает в очередь, просто ждет, когда поток пулов потоков станет доступным, что существенно повлияет на эффективную производительность пула потоков.

  2. Попросите, чтобы процедура Main () отслеживала, когда что-то происходило, и как долго каждый из них запускался дальше. Вместо каждой команды, говорящей «да, я готов» или «нет, я не», которая будет одинаковой для каждой команды, просто есть поля LastRun и Interval, которые затем Main () может использовать, чтобы определить, когда нужно выполнить каждую команду. .

  3. Не используйте очередь. Хотя это может показаться операцией типа очереди, поскольку каждая команда имеет свой интервал, на самом деле это не обычная очередь. Вместо этого поместите все команды в список, а затем отсортируйте список по кратчайшему времени до следующего запуска. Спите поток, пока первая команда не нужна для запуска. Запустите эту команду. Прибегните к списку следующей командой для запуска. Спать. Повторите.

  4. Не использовать несколько потоков. Если интервал каждой команды составляет минуту или несколько минут, вам, вероятно, вообще не нужно использовать потоки. Вы можете упростить все действия в одном потоке.

  5. Обработка ошибок. Подобные вещи требуют обширной обработки ошибок, чтобы убедиться, что проблема в одной команде не приводит к сбою всего цикла, и, таким образом, вы можете отлаживать проблему, когда она возникает. Вы также можете решить, следует ли команде немедленно повторить попытку при ошибке или дождаться следующего запланированного запуска или даже отложить ее больше, чем обычно. Вы также можете не регистрировать ошибку в команде, если ошибка возникает каждый раз (ошибка в часто выполняемой команде может легко создать огромные файлы журнала).

6 голосов
/ 30 января 2010

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

Определите свою работу следующим образом:

class MyFirstJob : CronJob
{
    public override void Execute()
    {
        // Put your logic here.
    }
}

И создайте основную точку входа для своего приложения, включая настройку расписания, например:

class Program
{
    static void Main(string[] args)
    {
        Bootstrap.Init(args, ServiceSetup);
    }

    static void ServiceSetup(SchedulingService service)
    {
        service.Hourly().Run<MyFirstJob>();
        service.Daily().Run<MySecondJob>();
    }
}

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

Отказ от ответственности: я являюсь ведущим программистом в NCron, так что я могу быть немного предвзятым! ; -)

2 голосов
/ 17 февраля 2010

Теперь дни Parallel Extensions от Microsoft должны быть жизнеспособным вариантом для написания параллельного кода или выполнения каких-либо задач, связанных с потоками. Он обеспечивает хорошую абстракцию над пулом потоков и системными потоками, так что вам не нужно обязательно думать, чтобы выполнить задачу.

На мой взгляд, подумайте об этом. Кстати, ваш код чист.

Спасибо.

2 голосов
/ 27 января 2010

Я бы сделал все ваши классы команд неизменными , чтобы вы не беспокоились об изменениях состояния.

0 голосов
/ 27 января 2010

running переменная должна быть помечена как volatile, если ее состояние будет изменено другим потоком.

Что касается пригодности, почему бы просто не использовать таймер?

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