繁体   English   中英

使用阻塞收集和任务的经典生产者消费者模式 .net 4 TPL

[英]classic producer consumer pattern using blockingcollection and tasks .net 4 TPL

请看下面的伪代码

//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 创建的任务和 net 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> 文档中有一个示例。

class 专门设计用于使这变得微不足道。

您的第二个代码块看起来更好。 但是,启动一个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
            }
        }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM