Модель потребителя производителя, когда много товаров

У меня есть модель производитель-потребитель, работающая на один продукт. Как лучше всего реализовывать, когда производитель выпускает много товаров? Например, DataBaseEvent, GuiEvent и ControlEvent, которые потребитель должен использовать. В приведенном ниже коде показан шаблон для одного продукта (DataBaseEvent). Должен ли каждый тип события помещаться в отдельную очередь или события наследуют базовый класс, который может быть поставлен в очередь. Может быть, есть лучший паттерн при работе со многими типами событий?

class DataBaseEventArgs : EventArgs
{
    public string textToDB = "";
}

class Consumer
{
    private Producer mProducer = new Producer();
    private Queue<DataBaseEventArgs> mDataBaseEventQueue = new Queue<DataBaseEventArgs>();
    private static EventWaitHandle mDataBaseEventWaitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
    private Thread mDataBaseEventDequeueThread = null;

    public Consumer()
    {
        mDataBaseEventDequeueThread = new Thread(DataBaseDequeueEvent);
        mDataBaseEventDequeueThread.Start();
        mProducer.mDataBaseEventHandler += WhenDataBaseEvent;
    }

    protected void DataBaseDequeueEvent()
    {
        while (true)
        {
            DataBaseEventArgs e;
            lock (((ICollection)mDataBaseEventQueue).SyncRoot)
            {
                if (mDataBaseEventQueue.Count > 0)
                {
                    e = mDataBaseEventQueue.Dequeue();
                }
            }
            // WriteToDatabase(e.textToDB);
            if (mDataBaseEventQueue.Count == 0)
            {
                mDataBaseEventWaitHandle.WaitOne(1000);
                mDataBaseEventWaitHandle.Reset();
            }
        }
    }

    internal void WhenDataBaseEvent(object sender, DataBaseEventArgs e)
    {
        lock (((ICollection)mDataBaseEventQueue).SyncRoot)
        {
            mDataBaseEventQueue.Enqueue(e);
            mDataBaseEventWaitHandle.Set();
        }
    }
}

class Producer
{
    public event EventHandler<DataBaseEventArgs> mDataBaseEventHandler = null;

    public void SendDataBaseEvent()
    {
        if (mDataBaseEventHandler != null)
        {
            DataBaseEventArgs e = new DataBaseEventArgs();
            e.textToDB = "This text will be written to DB";
            mDataBaseEventHandler(this, e);
        }
    }
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
1 336
2

Ответы 2

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

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

Кроме того, если вы обрабатываете сообщения по-другому, то нет смысла усложнять шаблон.

Несколько очередей были бы полезны, если вы хотите активно разделить работу, т.е. иметь разные потоки / пулы для разных типов событий. Если вы хотите разделить нагрузку, есть другой вариант - использовать интерфейс (а не базовый класс). Базовый класс - это нормально, но я не могу придумать ничего, что могло бы передать базовый класс интерфейсу. Или даже просто делегат по работе!

Также - я не уверен, что вам нужно событие сброса в этом случае; вы часто можете обрабатывать производителя / потребителя с помощью только блокировки и Monitor.Pulse / Wait (что имеет меньше накладных расходов, поскольку не задействованы никакие объекты ОС - только управляемые объекты). Однако, если код в настоящее время стабилен, возможно, оставьте «как есть» - многопоточность достаточно сложна, чтобы разобраться с ней один раз, не говоря уже о двух ...

Но для справки это будет примерно так:

while(true) {
    T item;
    lock(lockObj) {
        if (queue.Count == 0) { // empty
            Monitor.Wait(lockObj);
            continue; // ensure there is genuinely something to do
        }
        item = queue.Dequeue();
    }
    // TODO: process item
}
...
void Add(T item) {
    lock(lockObj) {
        queue.Enqueue(item);
        if (queue.Count == 1) { // first
            Monitor.PulseAll(lockObj);
        }
    }
}

(и не забывайте использовать PulseAll при очистке очередей)

Спасибо за образец кода монитора. Думаю, я буду использовать это вместо EventWaitHandler.

humcfc 17.11.2008 16:39

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