Ответ 1
Вы бы использовали BlockingCollection<T>
. Вот пример в документации.
Этот класс специально разработан, чтобы сделать это тривиальным.
См. ниже псевдокод
//Single or multiple Producers produce using below method
void Produce(object itemToQueue)
{
concurrentQueue.enqueue(itemToQueue);
consumerSignal.set;
}
//somewhere else we have started a consumer like this
//we have only one consumer
void StartConsumer()
{
while (!concurrentQueue.IsEmpty())
{
if (concurrentQueue.TrydeQueue(out item))
{
//long running processing of item
}
}
consumerSignal.WaitOne();
}
Как я могу портировать этот шаблон, который я использовал с незапамятных времен, чтобы использовать созданные задачи taskfactory и новые функции сигнализации сети 4. Другими словами, если кто-то должен был написать этот шаблон, используя net 4, как бы он выглядел? Псевдокод в порядке. Я уже использую .net 4 concurrentQueue, как вы можете видеть. Как использовать задачу и, возможно, использовать какой-либо новый механизм сигнализации, если это возможно. спасибо
Решение моей проблемы ниже благодаря Jon/Dan. Милая. Никакой ручной сигнализации или while (true) или while (itemstoProcess) типа, как старые дни
//Single or multiple Producers produce using below method
void Produce(object itemToQueue)
{
blockingCollection.add(item);
}
//somewhere else we have started a consumer like this
//this supports multiple consumers !
task(StartConsuming()).Start;
void StartConsuming()
{
foreach (object item in blockingCollection.GetConsumingEnumerable())
{
//long running processing of item
}
}
cancellations are handled using cancel tokens
Вы бы использовали BlockingCollection<T>
. Вот пример в документации.
Этот класс специально разработан, чтобы сделать это тривиальным.
Второй блок кода выглядит лучше. Но, начиная с Task
, а затем сразу же ожидая, это бессмысленно. Просто позвоните Take
, а затем обработайте элемент, который возвращается непосредственно на поток потребления. Именно так должна быть разработана модель производителя-потребителя. Если вы считаете, что обработка рабочих элементов достаточно интенсивна, чтобы гарантировать большее количество потребителей, то, во что бы то ни стало, начинают больше потребителей. BlockingCollection
является безопасным для нескольких производителей и нескольких потребителей.
public class YourCode
{
private BlockingCollection<object> queue = new BlockingCollection<object>();
public YourCode()
{
var thread = new Thread(StartConsuming);
thread.IsBackground = true;
thread.Start();
}
public void Produce(object item)
{
queue.Add(item);
}
private void StartConsuming()
{
while (true)
{
object item = queue.Take();
// Add your code to process the item here.
// Do not start another task or thread.
}
}
}
Я использовал шаблон до того, как он создает своего рода потребитель "по требованию" (основанный на потреблении от ConcurrentQueue):
private void FireAndForget(Action fire)
{
_firedEvents.Enqueue(fire);
lock (_taskLock)
{
if (_launcherTask == null)
{
_launcherTask = new Task(LaunchEvents);
_launcherTask.ContinueWith(EventsComplete);
_launcherTask.Start();
}
}
}
private void LaunchEvents()
{
Action nextEvent;
while (_firedEvents.TryDequeue(out nextEvent))
{
if (_synchronized)
{
var syncEvent = nextEvent;
_mediator._syncContext.Send(state => syncEvent(), null);
}
else
{
nextEvent();
}
lock (_taskLock)
{
if (_firedEvents.Count == 0)
{
_launcherTask = null;
break;
}
}
}
}
private void EventsComplete(Task task)
{
if (task.IsFaulted && task.Exception != null)
{
// Do something with task Exception here
}
}