Производитель потребительский образец, когда много продуктов - PullRequest
2 голосов
/ 17 ноября 2008

У меня есть шаблон производитель-потребитель, работающий на один продукт. Какова лучшая реализация, когда производитель производит много продуктов? Например, 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);
        }
    }
}

Ответы [ 2 ]

4 голосов
/ 17 ноября 2008

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

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

Но для справки это было бы что-то вроде:

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 при очистке очередей)

0 голосов
/ 17 ноября 2008

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

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

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

...