Как выполнять программирование, управляемое событиями, между двумя отдельными программами на C#?

StackOverflow https://stackoverflow.com/questions/1339243

  •  20-09-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

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

Это было полезно?

Решение

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

Если MSMQ невозможен, вы также можете использовать WCF.Вместо публикации/подписки в WCF вы можете выбрать модель сообщений FAF (выпустить и забыть).TP опубликует услугу, которую будет использовать TC.TC нужно будет только отправить сообщение службе TP, чтобы уведомить TP о новых задачах.Обратной стороной этой модели является то, что TC зависит от TP, что может быть меньше, чем идея.Для успешного функционирования TC также должен быть запущен TP, поскольку он зависит от службы 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, что позволяет вам аккуратно завершить поток без принудительного прерывания.

Другие советы

Когда нет новых задач, бесполезно запускать оператор SQL select fromwhere.

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

Проверить Уведомления о запросах 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();

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top