Как выполнить управляемое событиями программирование между двумя отдельными программами C #? - PullRequest
4 голосов
/ 27 августа 2009

Как запустить событие из отдельной программы на C #?

Программа на C #, над которой я работаю, состоит из двух отдельных компонентов: Task Creator (TC) и Task Processor (TP). TC привязан к веб-сервису, который постоянно вставляет новые задачи в таблицу базы данных. С другой стороны, TP читает из той же таблицы и обрабатывает каждую задачу, а затем обновляет статус до той же таблицы. Это почти как очередь, но сделано с использованием базы данных, а не, например. MSMQ. Каждые 5 секунд TP просыпается и читает данные из таблицы, чтобы проверить наличие необработанных задач, однако это оказывает некоторое влияние на производительность. Когда нет новых задач, это пустая трата на запуск оператора SQL выбора. Идеальный способ - это использовать какой-то метод уведомления, чтобы при вставке новых задач TP получал уведомления, а затем просыпался от мечты проверять новые задачи.

Текущее решение:

диаграмма текущего решения http://yuml.me/3b49bcfd

Идеальное решение:

диаграмма идеального решения http://yuml.me/5cf843a5

Ответы [ 3 ]

4 голосов
/ 27 августа 2009

Я бы порекомендовал MSMQ. :) Я не уверен, почему вы не используете его, однако вы упомянули об этом в своем вопросе. Это в значительной степени именно то, что MSMQ был разработан для ... длительных событий между приложениями. Он в первую очередь поддерживает модель сообщений pub / sub ... которая на основе вашего "идеального решения" - именно то, что вам нужно: TC - издатель, TP - подписчик. TC регистрирует задачу, а затем отбрасывает сообщение в своей очереди публикации. Задача TP не должна быть запущена и запущена для TC, чтобы успешно отбрасывать сообщение в своей очереди, однако, когда задача TP работает, она будет получать уведомления и обрабатывать сообщения в очереди в порядке приоритета поступления.

Если MSMQ не вариант, вы также можете использовать WCF. Вместо pub / sub, с WCF вы можете выбрать модель сообщения FAF (запустить и забыть). TP будет публиковать сервис, который будет использовать TC. TC нужно будет только отправить сообщение службе TP, чтобы уведомить TP о новых задачах. Недостатком этой модели является то, что TC зависит от TP, что может быть меньше, чем идея. TP также должен быть запущен для успешного функционирования TC, поскольку он зависит от сервиса TP. При использовании подхода MSMQ ни TP, ни TC не зависят друг от друга, они зависят только от MSMQ (подход с более низкой связью).

РЕДАКТИРОВАТЬ:

Пример использования MSMQ для запуска событий из TC и ответа на события в TP.

// TC message queue manager, sends messages
public class TaskMessageQueueManager
{
  public void NotifySubscribersOfNewTasks()
  {
    var queue = getQueue(".\private$\TaskNotifications");
    queue.Send("Tasks waiting.");
  }

  private MessageQueue getQueue(string name)
  {
    MessageQueue queue = null;
    try
    {
      if (!MessageQueue.Exists(name))
      {
        queue = MessageQueue.Create(name);
      }
      else
      {
        queue = new MessageQueue(name);
      }
    } 
    catch (Exception ex)
    {
      throw new InvalidOperationException("An error occurred while retrieving the message queue '" + name + "'.", ex);
    }

    return queue;
  }
}

// TP message queue handler, receives messages
public class TaskMessageQueueHandler
{
  private Thread m_thread;
  private ManualResetEvent m_signal;

  public void Start()
  {
    m_signal = new ManualResetEvent(false);
    m_thread = new Thread(MSMQReceiveLoop);
    m_thread.Start();

  }

  public void Stop()
  {
    m_signal.Set();
  }

  private void MSMQReceiveLoop()
  {
    bool running = true;
    MessageQueue queue = getQueue(".\private$\TaskNotifications");

    while (running)
    {
      try
      {
        var message = queue.Receive(); // Blocks here until a message is received by MSMQ

        if (message.Body.ToString() == "Tasks waiting.")
        {
          // TODO: Fire off process, perhaps another thread, to handle waiting tasks
        }

        if (m_signal.WaitOne(10)) // Non-blocking check for exit signal
        {
          running = false; // If Stop method has been called, the signal will be set and we can end loop
        } 
      }
      catch
      {
         // handle error
         running = false;
      }
    }
  }
}

Сообщение не должно быть простым текстом. Вы можете отправить объект или граф объекта, и он автоматически будет сериализован и отформатирован как XML по умолчанию. Я считаю, что вы также можете сериализовать данные в двоичном формате, если это то, что вам нужно. В любом случае, вы заметите, что нигде нет вызовов или опросов Thread.Sleep. Цикл завершается на основе ManualResetEvent, позволяя вам аккуратно завершить поток без принудительной отмены.

2 голосов
/ 27 августа 2009

Когда новых задач нет, запускать оператор SQL выбора из где-то немного напрасно.

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

2 голосов
/ 27 августа 2009

Извлечение Уведомления о запросах SQL Server 2005 . Я только что узнал, что кажется, что он взят из SQL Server 2008, так что, возможно, это не самая лучшая идея.

Во-вторых, MSMQ, вероятно, намного лучше. В сочетании с nServiceBus вы можете получить победителя.

Другим подходом могут быть события синхронизации потоков.

В TP у вас может быть что-то вроде:

EventWaitHandle taskEvent = new EventWaitHandle(true,
                EventResetMode.AutoReset,
                "newTask",
                out wasCreated);
new Thread(WaitForTask).Start();
...

public void WaitForTask() { while (true) { taskEvent.WaitOne(); ProcessTasks();} }

А в ТС:

bool eventExist;
while (!eventExist)
{
    try
    {
        taskEvent= EventWaitHandle.OpenExisting("newTask");
        eventExist = true;
    }
    catch (WaitHandleCannotBeOpenedException)
    {
        eventExist = false;
        Thread.Sleep(1000);
    }
}

CreateNewTask();
taskEvent.Set();

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

...