Question

Comment tirer en cas d'un programme distinct C #?

Le programme C # Je travaille sur deux éléments distincts: Créateur de tâches (TC) et processeur des tâches (TP). TC est attaché à un service Web qui insère constamment de nouvelles tâches dans une table de base de données. D'autre part TP se lit de la même table et traite ensuite chaque tâche met à jour l'état à la même table. Il est presque comme une file d'attente, mais fait en utilisant la base de données plutôt que par exemple MSMQ. Toutes les 5 secondes TP se réveille et se lit de la table pour vérifier les tâches non traitées mais cela a des incidences sur le rendement. Quand il n'y a pas de nouvelles tâches, il est un peu de déchets pour tirer une sélection d'où l'instruction SQL. Le moyen idéal est d'avoir une sorte de méthode de notification lorsque de nouvelles tâches sont insérées TP recevront une notification et se réveille alors de son rêve pour vérifier de nouvelles tâches.

Solution actuelle:

schéma de la solution actuelle http://yuml.me/3b49bcfd

Solution idéale:

diagramme de idealsolution http://yuml.me/5cf843a5

Était-ce utile?

La solution

Je recommande MSMQ. :) Je ne sais pas pourquoi vous ne l'utilisez pas, mais vous avez mentionné dans votre question. Ceci est à peu près exactement ce que MSMQ a été conçu pour ... concours complet durable entre les applications. Il soutient principalement le pub / sous modèle de message ... qui en fonction de votre « solution idéale » est exactement ce dont vous avez besoin: TC est l'éditeur, TP est un abonné. TC enregistre la tâche, tombe alors un message dans sa file d'attente publier. La tâche de TP n'a pas besoin d'être opérationnel pour TC de laisser tomber avec succès un message dans sa file d'attente, mais lorsque la tâche de TP est en cours d'exécution, il recevra des notifications et gérer les messages dans la file d'attente dans l'ordre de priorité l'arrivée.

Si MSMQ est pas une option, vous pouvez également utiliser WCF. Plutôt que de pub / sub, avec WCF, vous pouvez opter pour un modèle de message FAF (incendie et oublier). TP publierait un service TC consommerait. TC aurait seulement besoin de tirer un message hors au service de TP d'aviser TP de nouvelles tâches. L'inconvénient de ce modèle est que TC dépend de TP, ce qui pourrait être inférieure à idée. TP doit également être en cours d'exécution pour TC de fonctionner avec succès, car il dépend du service de TP. Avec l'approche MSMQ, ni TP ni TC dépendent les uns des autres, ils ne dépendent que sur MSMQ (une approche de couplage plus faible.)

EDIT:

Un exemple de la façon d'utiliser MSMQ pour déclencher des événements de TC et répondre aux événements dans 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;
      }
    }
  }
}

Le message ne doit pas être un texte simple. Vous pouvez envoyer un graphe d'objet ou d'un objet, et il sera automatiquement sérialisé et formaté en XML par défaut. Je crois que vous pouvez également sérialiser des données dans un format binaire, si c'est ce dont vous avez besoin. De toute façon, vous remarquerez qu'il n'y a pas d'appels Thread.sleep ou sondages partout. Les sorties en boucle à partir d'un ManualResetEvent, vous permettant de mettre fin à proprement le fil sans disque abort.

Autres conseils

  

Quand il n'y a pas de nouvelles tâches, il est un peu de déchets pour tirer une sélection d'où l'instruction SQL.

Une sélection sur une seule table, toutes les 5 secondes avec des critères simples et des lignes de coûts généralement aucun ont retourné à côté de rien, ne vous inquiétez pas.

Consultez SQL Server 2005 Query Notifications . Je viens d'apprendre qu'il semble qu'il a été tiré de SQL Server 2008 de sorte qu'il pourrait ne pas être la meilleure idée après tout.

Je seconde que MSMQ est probablement une bien meilleure façon. Combiné avec nServiceBus vous pourriez avoir un gagnant.

Une autre approche pourrait être des événements de synchronisation de fil.

Dans TP, vous pouvez avoir quelque chose comme:

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

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

Et dans TC:

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

CreateNewTask();
taskEvent.Set();

Non que je vois comment un appel tous les cinq secondes pourrait être un porc de performance.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top