title: Best way to limit the number of active Tasks running via the Parallel Task Library
body: <p>Consider a queue holding a <strong>lot</strong> of jobs that need processing. Limitation of queue is can only get 1 job at a time and no way of knowing how many jobs there are. The jobs take 10s to complete and involve a lot of waiting for responses from web services so is not CPU bound.</p>
  
  <p>If I use something like this</p>
  
  <pre><code>while (true)
  {
     var job = Queue.PopJob();
     if (job == null)
        break;
     Task.Factory.StartNew(job.Execute); 
  }
  </code></pre>
  
  <p>Then it will furiously pop jobs from the queue much faster than it can complete them, run out of memory and fall on its ass. >.&lt;</p>
  
  <p>I can't use (I don't think) <a href="http://msdn.microsoft.com/en-us/library/system.threading.tasks.paralleloptions.aspx" rel="noreferrer">ParallelOptions.MaxDegreeOfParallelism</a> because I can't use Parallel.Invoke or Parallel.ForEach </p>
  
  <p>3 alternatives I've found</p>
  
  <ol>
  <li><p>Replace Task.Factory.StartNew with</p>
  
  <pre><code>Task task = new Task(job.Execute,TaskCreationOptions.LongRunning)
  task.Start();
  </code></pre>
  
  <p>Which seems to somewhat solve the problem but I am not <a href="https://stackoverflow.com/questions/3488381/does-the-task-parallel-library-or-plinq-take-other-processes-into-account">clear exactly what this is doing</a> and if this is the best method.</p></li>
  <li><p>Create a <a href="http://msdn.microsoft.com/en-us/library/ee789351.aspx" rel="noreferrer">custom task scheduler that limits the degree of concurrency</a></p></li>
  <li><p>Use something like <a href="http://msdn.microsoft.com/en-us/library/dd997371.aspx" rel="noreferrer">BlockingCollection</a> to add jobs to collection when started and remove when finished to limit number that can be running.</p></li>
  </ol>
  
  <p>With #1 I've got to trust that the right decision is automatically made, #2/#3 I've got to work out the max number of tasks that can be running myself.</p>
  
  <p>Have I understood this correctly - which is the better way, or is there another way?</p>
  
  <p><strong>EDIT</strong> - This is what I've come up with from the answers below, producer-consumer pattern.</p>
  
  <p>As well as overall throughput aim was not to dequeue jobs faster than could be processed and not have multiple threads polling queue (not shown here but thats a non-blocking op and will lead to huge transaction costs if polled at high frequency from multiple places).</p>
  
  <pre><code>// BlockingCollection&lt;&gt;(1) will block if try to add more than 1 job to queue (no
  // point in being greedy!), or is empty on take.
  var BlockingCollection&lt;Job&gt; jobs = new BlockingCollection&lt;Job&gt;(1);
  
  // Setup a number of consumer threads.
  // Determine MAX_CONSUMER_THREADS empirically, if 4 core CPU and 50% of time
  // in job is blocked waiting IO then likely be 8.
  for(int numConsumers = 0; numConsumers &lt; MAX_CONSUMER_THREADS; numConsumers++)
  {
     Thread consumer = new Thread(() =&gt;
     {
        while (!jobs.IsCompleted)
        {
           var job = jobs.Take();
           job.Execute();
        }
     }
     consumer.Start();
  }
  
  // Producer to take items of queue and put in blocking collection ready for processing
  while (true)
  {
      var job = Queue.PopJob();
      if (job != null)
         jobs.Add(job);
      else
      {
         jobs.CompletedAdding()
         // May need to wait for running jobs to finish
         break;
      }
  }
  </code></pre>