Reputation: 224039
I've got a loop like this
ICollection<Data> GetData()
{
ICollection<Data> result = new List<Data>()
foreach (var item in aCollection)
item.AddData(result);
return result;
}
and I now need this to be executed in parallel instead iteratively. My first attempt was to do soemthing like this
ICollection<Data> GetData()
{
ICollection<Data> result = new SynchronizedCollection<Data>()
foreach (var item in aCollection)
new Thread(delegate() { item.AddData(result); }).Start();
return result;
}
but I need a way to wait for all the data to be added before I return the result.
What would be the simplest way to do this?
Edit: That AddData
will call across a network. In the collection usually are up to a few dozen entries.
Upvotes: 2
Views: 1927
Reputation: 12336
You can use Parallel Extensions which will be integrated in C# 4.0 and are available for C# 3.5 as separate library which you can download here: Microsoft Parallel Extensions to .NET Framework 3.5.
If you don't want to use Parallel Extensions, do not start a thread for every iteration, rather use ThreadPool instead, which enables better performance.
As I got to know in the comments of this answer, List<> is not thread-safe why you should use SynchronizedCollection<> instead.
Here is a code sample using thread pool.
IEnumerable<object> providers = null;
var waitHandles = new List<WaitHandle>();
foreach (var provider in providers)
{
var resetEvent = new ManualResetEvent(false);
waitHandles.Add(resetEvent);
ThreadPool.QueueUserWorkItem(s =>
{
// do whatever you want.
((EventWaitHandle)s).Set();
}, resetEvent);
}
WaitHandle.WaitAll(waitHandles.ToArray());
Upvotes: 2
Reputation: 22829
The simplest way is probably to wait for the parallels framework coming in 4.0.
Right ow, for starters, you need to be careful abut the thread creation there. If you have several hundreds or even thousands of items, that code will potentially kill your app, or at least your performance.
I would attempt to design the AddData method as an asynchronous call. The IAsyncResult has a WaitHandle. You can wait on those handles until all asyncresults state that the operation is done. Then you can carry on. Doing this stuff asynchronously should ensure that you use threads from the thread pool. That way you get pretty good performance and you reach a natural saturation of working threads if your list gets really large.
Upvotes: 0
Reputation: 116401
Unless AddData is really, really slow the overhead of creating new threads will most likely be the bottleneck in your code.
If you do want to hand this off to other threads you should use the ThreadPool for this. As for waiting for the threads to complete, you can use wait handles to signal between the threads.
Upvotes: 2
Reputation: 67362
Store references to the thread objects you created and call join on every one of them:
ICollection<Data> GetData()
{
ICollection<Data> result = new SynchronizedCollection<Data>()
List<Thread> threads=new List<Thread>();
foreach (var item in aCollection)
{
Thread thread=new Thread(delegate() { item.AddData(result); });
thread.Start();
threads.Add(thread);
}
foreach(Thread thread in threads)
thread.Join();
return result;
}
Upvotes: -1
Reputation: 31212
In C#4.0, you can use something like this:
Parallel.ForEach<Data>(aCollection, delegate(Data d)
{
d.AddData(result);
});
Upvotes: 1