كيفية القيام الحدث برمجة مدفوعة بين برامج منفصلة C #؟

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

  •  20-09-2019
  •  | 
  •  

سؤال

كيفية قيادة الحدث من برنامج منفصل C #؟

برنامج C # الذي أعمل فيه على مكونين منفصلين: إنشاء المهام (TC) ومعالج المهام (TP). يتم إرفاق TC بخدمة ويب تقوم باستمرار بإدراج مهام جديدة في جدول قاعدة البيانات. من ناحية أخرى يقرأ TP من نفس الجدول ويعالج كل مهام ثم يقوم بتحديث الحالة مرة أخرى إلى نفس الجدول. انها تقريبا مثل قائمة الانتظار ولكن تم القيام باستخدام قاعدة البيانات بدلا من مثال MSMQ. يستيقظ TP كل 5 ثوان ويقرأ من الجدول للتحقق من المهام غير المجهزة ولكن هذا له بعض تأثيرات الأداء. عندما لا تكون هناك مهام جديدة، فهو قليل من النفايات لإطلاق اختيار من حيث عبارة SQL. الطريقة المثالية هي أن يكون لديك نوع من طريقة الإعلام التي عند إدراج مهام جديدة ستصبح إخطارا، ثم يستيقظ من حلمها للتحقق من مهام جديدة.

الحل الحالي:

مخطط الحل الحالي http://yuml.me/3b49bcd

حل مثالي:

رسم تخطيطي للحضور المثالي http://yuml.me/5cf843a5

هل كانت مفيدة؟

المحلول

أود أن أوصي MSMQ. :) أنا لست متأكدا من السبب في أنك لا تستخدمه، ومع ذلك أنك ذكرت ذلك في سؤالك. هذا هو بالضبط ما صممه MSMQ بالضبط ... دائم الأحداث بين التطبيقات. يدعم بشكل أساسي نموذج الرسائل / الرسالة الفرعية ... التي تعتمد على "الحل المثالي" هو بالضبط ما تحتاجه: TC هو الناشر، TP هو مشترك. يسجل TC المهمة، ثم يسقط رسالة في قائمة انتظار النشر. ومع ذلك، فإن مهمة TP لا تحتاج إلى أن تكون قيد التشغيل وتشغيلها لإسقاط رسالة بنجاح في قائمة انتظارها، إلا عندما تعمل مهمة TP، وسوف تتلقى الإخطارات والتعامل مع الرسائل في قائمة الانتظار في الطلب الأول الأول.

إذا لم يكن MSMQ خيارا، فيمكنك أيضا استخدام WCF. بدلا من حانة / فرعية، مع 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 افتراضيا. أعتقد أنه يمكنك أيضا تسلسل البيانات في شكل ثنائي، إذا كان هذا هو ما تحتاجه. في كلتا الحالتين، ستلاحظ أنه لا يوجد خيط. المكالمات أو الاقتراع في أي مكان. مخارج حلقة بناء على ManualResetevent، مما يتيح لك إنهاء الموضوع نظيف دون إحباط صلب.

نصائح أخرى

عندما لا تكون هناك مهام جديدة، فهو قليل من النفايات لإطلاق اختيار من حيث عبارة SQL.

حدد على طاولة واحدة، كل 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();} }

وفي TC:

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