我有一个生产者 - 消费者模式为一种产品工作。当生产者生产许多产品时,最佳实施是什么?例如,消费者应使用的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);
}
}
}
答案 0 :(得分:4)
如果要主动分离工作,多个队列将非常有用 - 即,为不同类型的事件设置不同的线程/池。如果要共享负载,还有另一种选择 - 使用接口(而不是基类)。基类是好的,但我想不出任何会在接口上强制基类的东西。或者甚至只是代表参加工作!
另外 - 在这种情况下我不确定你需要重置事件;您通常可以使用lock和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)
答案 1 :(得分:0)
我认为如果它们具有相同的优先级并且将以类似的方式处理,那么将所有请求排队到一个队列会更好。
如果其中一个请求的概率较高,那么您需要一些花哨的优先级队列,或者您可以使用不同的队列。
此外,如果您以不同的方式处理消息,那么没有必要使模式过于复杂。