Если у вас есть .Net 4.0 или выше вы можете сделать это таким образом, используя BlockingCollection
int maxBufferCap = 500;
BlockingCollection<MagicalObject> Collection
= new BlockingCollection<MagicalObject>(maxBufferCap);
void Producer()
{
while (magic.HasMoreMagic)
{
this.Collection.Add(magic.ProduceMagic());
}
this.Collection.CompleteAdding();
}
void Consumer()
{
foreach (MagicalObject magicalObject in this.Collection.GetConsumingEnumerable())
{
DoSomthing(magicalObject);
}
}
В foreach
линия будет спать, если нет данных в буфере, он автоматически автоматически разбудит его, когда что-то добавится в коллекцию.
Причина, по которой я устанавливаю максимальный буфер, заключается в том, что ваш производитель намного быстрее, чем потребитель, который может в конечном итоге потреблять много памяти, поскольку все больше и больше объектов попадают в коллекцию. Установив максимальный размер буфера при создании коллекции блокировки при достижении размера буфера, вызов Add
на производителя будет блокироваться, пока элемент не будет удален из коллекции потребителем.
Еще один бонус класса BlockingCollection
- он может иметь столько производителей и потребителей, сколько вам нужно, это не должно быть соотношение 1: 1. Если DoSomthing
поддерживает его, вы могли бы иметь foreach
петли на ядро компьютера (или даже использовать Parallel.ForEach
и использовать потребляющие перечислимы в качестве источника данных)
void ConsumersInParalell()
{
//This assumes the method signature of DoSomthing is one of the following:
// Action<MagicalObject>
// Action<MagicalObject, ParallelLoopState>
// Action<MagicalObject, ParallelLoopState, long>
Paralell.ForEach(this.Collection.GetConsumingEnumerable(), DoSomthing);
}
Какую версию .Net вы используете, есть несколько новых вещей для v4 для именно этого материала. –
.Net 3.5; Комментарии должны содержать не менее 15 символов. –