Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use asynchronous delegates or ThreadPool.QueueUserWorkItem for massive parallelism?

I have a .NET application that processes around 300,000 records in a batch import, and it takes a few seconds per record so I would like to parallelize this. In the following code, what's the difference between ProcessWithAnsycDelegates() and ProcessWithThreadPool()?

public class ResultNotification
 { public EventHandler event Success;
   public EventHandler event Fail;
   internal void Notify(bool sucess) {if (success) Success(); else Fail();}
 }

public static class Processor
 { public ResultNotification ProcessWithAnsycDelegates(Record record)
    { var r = new ResultNotification();
      Func<Record,bool> processRecord=new RecordProcessor().ProcessRecord;
      processRecord.BeginInvoke
                     ( record
                      ,ar => result.Notify(processRecord.EndInvoke(ar))
                      ,null); 
      return r;    
    }

   public ResultNotification ProcessWithThreadPool(Record r)
    { var r  = new ResultNotification();
      var rp = new RecordProcessor();
      ThreadPool.QueueWorkUserItem(_=>result.Notify(rp.ProcessRecord(r)));
      return r;
    }
 }
like image 670
Mark Cidade Avatar asked Oct 10 '08 18:10

Mark Cidade


2 Answers

The literal answer to the question is that both use the threadpool, so the difference is not much if performance is the only consideration.

If the question is really about getting the best performance, then it may help to know that using the threadpool does have issues. These include:

  • Lock contention on the work queue
  • Excessive context switching. If you have 2 CPUs and a sequence of work items then 25 threads don't really help. Better to have 2 threads, one for each CPU

It might be worth investigating the TPL and PLINQ:

  • Parallel LINQ Running Queries On Multi-Core Processors
  • Parallel Performance Optimize Managed Code For Multi-Core Machines
  • Improved Support For Parallelism In The Next Version Of Visual Studio

One example they give of the TPL in use is:

for (int i = 0; i < 100; i++) { 
  a[i] = a[i]*a[i]; 
}

to:

Parallel.For(0, 100, delegate(int i) { 
  a[i] = a[i]*a[i]; 
});
like image 81
Thomas Bratt Avatar answered Sep 28 '22 17:09

Thomas Bratt


In this case, not a lot as they both use the threadpool under the hood. I'd say that the QueueUserWorkItem() is easier to read and see what's going on vs. BeginInvoke.

This link may help. It's older information, but still mostly applicable http://www.yoda.arachsys.com/csharp/threads/threadpool.shtml

like image 45
chadmyers Avatar answered Sep 28 '22 18:09

chadmyers