C#生产者/消费者 [英] C# producer/consumer
问题描述
我最近碰到一个生产者/消费者模式c#实现。这是非常简单的(至少对我来说)非常优雅。
这似乎已经在2006年左右提出的,所以我在想,如果这个实现
- 安全
- 仍然适用
code是低于(原来的code以<引用href=\"http://bytes.com/topic/net/answers/575276-producer-consumer#post2251375\">http://bytes.com/topic/net/answers/575276-producer-consumer#post2251375)
使用系统;
System.Collections中使用;
使用的System.Threading;公共类测试
{
静态ProducerConsumer队列中; 静态无效的主要()
{
队列=新ProducerConsumer();
新主题(新的ThreadStart(ConsumerJob))启动()。 随机RNG =新的随机(0);
的for(int i = 0;我小于10;我++)
{
Console.WriteLine(生产{0},我);
queue.Produce(ⅰ);
Thread.sleep代码(rng.Next(1000));
}
} 静态无效ConsumerJob()
{
//确保我们从得到一个不同的随机种子
//第一个线程
随机RNG =新的随机(1);
//我们碰巧知道我们只得到了10
//物品接收
的for(int i = 0;我小于10;我++)
{
对象o = queue.Consume();
Console.WriteLine(\\ t \\ t \\ t \\ tConsuming {0},O);
Thread.sleep代码(rng.Next(1000));
}
}
}公共类ProducerConsumer
{
只读对象listLock =新的对象();
排队长龙=新队列(); 公共无效农产品(对象o)
{
锁定(listLock)
{
queue.Enqueue(O); //我们总是需要脉冲,即使队列不是
//空了。否则,如果我们添加几个项目
//临门,我们可能只脉动一次,醒来
//单个线程时,即使有多个线程
//等待项目。
Monitor.Pulse(listLock);
}
} 公共消费对象()
{
锁定(listLock)
{
//如果队列为空,等待要增加一个项目
//注意,这是一个while循环,因为我们可以是脉冲
//但没有醒来另一个线程进来前,
//消耗的新添加的对象。在这种情况下,我们将
//必须等待另一个脉冲。
而(queue.Count == 0)
{
//这将释放listLock,只有重新获得它
//后被唤醒通过调用脉冲
Monitor.Wait(listLock);
}
返回queue.Dequeue();
}
}
}
在code是比旧的 - 我写了一些时间才.NET 2.0就出来了。在概念的的生产者/消费者队列的办法的比旧的,虽然:)
是的,code是安全的,因为据我所知 - 但它有一些不足之处:
- 这是不通用的。现代版的肯定是通用的。
- 它没有停止队列的方式。停止队列(让所有的消费者线程退休)的一个简单的方法是有一个停止工作的令牌,该令牌可放入队列。然后,你有线程添加尽可能多的令牌。或者,你有一个独立的标志,表示要停止。 (这允许其他线程完成所有当前工作在队列前停止。)
- 如果作业是非常小的,在耗时一个作业可能不是最有效的事情。
在code背后的思想比code本身更重要的,是诚实的。
i've recently come across a producer/consumer pattern c# implementation. it's very simple and (for me at least) very elegant.
it seems to have been devised around 2006, so i was wondering if this implementation is
- safe
- still applicable
Code is below (original code was referenced at http://bytes.com/topic/net/answers/575276-producer-consumer#post2251375)
using System;
using System.Collections;
using System.Threading;
public class Test
{
static ProducerConsumer queue;
static void Main()
{
queue = new ProducerConsumer();
new Thread(new ThreadStart(ConsumerJob)).Start();
Random rng = new Random(0);
for (int i=0; i < 10; i++)
{
Console.WriteLine ("Producing {0}", i);
queue.Produce(i);
Thread.Sleep(rng.Next(1000));
}
}
static void ConsumerJob()
{
// Make sure we get a different random seed from the
// first thread
Random rng = new Random(1);
// We happen to know we've only got 10
// items to receive
for (int i=0; i < 10; i++)
{
object o = queue.Consume();
Console.WriteLine ("\t\t\t\tConsuming {0}", o);
Thread.Sleep(rng.Next(1000));
}
}
}
public class ProducerConsumer
{
readonly object listLock = new object();
Queue queue = new Queue();
public void Produce(object o)
{
lock (listLock)
{
queue.Enqueue(o);
// We always need to pulse, even if the queue wasn't
// empty before. Otherwise, if we add several items
// in quick succession, we may only pulse once, waking
// a single thread up, even if there are multiple threads
// waiting for items.
Monitor.Pulse(listLock);
}
}
public object Consume()
{
lock (listLock)
{
// If the queue is empty, wait for an item to be added
// Note that this is a while loop, as we may be pulsed
// but not wake up before another thread has come in and
// consumed the newly added object. In that case, we'll
// have to wait for another pulse.
while (queue.Count==0)
{
// This releases listLock, only reacquiring it
// after being woken up by a call to Pulse
Monitor.Wait(listLock);
}
return queue.Dequeue();
}
}
}
The code is older than that - I wrote it some time before .NET 2.0 came out. The concept of a producer/consumer queue is way older than that though :)
Yes, that code is safe as far as I'm aware - but it has some deficiencies:
- It's non-generic. A modern version would certainly be generic.
- It has no way of stopping the queue. One simple way of stopping the queue (so that all the consumer threads retire) is to have a "stop work" token which can be put into the queue. You then add as many tokens as you have threads. Alternatively, you have a separate flag to indicate that you want to stop. (This allows the other threads to stop before finishing all the current work in the queue.)
- If the jobs are very small, consuming a single job at a time may not be the most efficient thing to do.
The ideas behind the code are more important than the code itself, to be honest.
这篇关于C#生产者/消费者的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!