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

前端 未结 3 1826
醉酒成梦
醉酒成梦 2020-12-05 07:49

Please see below pseudo code

//Single or multiple Producers produce using below method
    void Produce(object itemToQueue)
    {
        concurrentQueue.enq         


        
相关标签:
3条回答
  • 2020-12-05 08:12

    I've used a pattern before that creates a sort of 'on-demand' queue consumer (based on consuming from a 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
                }
            }
    
    0 讨论(0)
  • 2020-12-05 08:30

    You would use BlockingCollection<T>. There's an example in the documentation.

    That class is specifically designed to make this trivial.

    0 讨论(0)
  • 2020-12-05 08:38

    Your second block of code looks better. But, starting a Task and then immediately waiting on it is pointless. Just call Take and then process the item that is returned directly on the consuming thread. That is how the producer-consumer pattern is meant to be done. If you think the processing of work items is intensive enough to warrant more consumers then by all means start more consumers. BlockingCollection is safe multiple producers and multiple consumers.

    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. 
        }
      }
    }
    
    0 讨论(0)
提交回复
热议问题