views:

195

answers:

2

I'm hoping to get some advice on the use of thread managment and hopefully the task parallel library, because I'm not sure I've been going down the correct route. Probably best is that I give an outline of what I'm trying to do.

Given a Problem I need to generate a Solution using a heuristic based algorithm. I start of by calculating a base solution, this operation I don't think can be parallelised so we don't need to worry about.

Once the inital solution has been generated, I want to trigger n threads, which attempt to find a better solution. These threads need to do a couple of things:

  1. They need to be initalized with a different 'optimization metric'. In other words they are attempting to optimize different things, with a precedence level set within code. This means they all run slightly different calculation engines. I'm not sure if I can do this with the TPL..
  2. If one of the threads finds a better solution that the currently best known solution (which needs to be shared across all threads) then it needs to update the best solution, and force a number of other threads to restart (again this depends on precedence levels of the optimization metrics).
  3. I may also wish to combine certain calculations across threads (e.g. keep a union of probabilities for a certain approach to the problem). This is probably more optional though.
  4. The whole system needs to be thread safe obviously and I want it to be running as fast as possible.

I tried quite an implementation that involved managing my own threads and shutting them down etc, but it started getting quite complicated, and I'm now wondering if the TPL might be better. I'm wondering if anyone can offer any general guidance?

Thanks...

A: 

This is going to be complicated no matter how you do it. Writing proper synchronization code is very difficult. And I think that TPL will be overkill for this.

My recommendation would be to sit back and look at the problem and white board it out and try to remove as much complexity as possible.

Maybe this will help... Create a queue of optimization metrics and a shared class with the best answer. Guard your shared class with a reader writer lock and your queue with a mutex or some other lock. Start up 4-8 threads (one thread per CPU, or more if you block a lot) and have them run in a loop. Remove an item from the queue, process it, check the shared data, repeat until no more items.

Resist the temptation to start up 3,000 threads and be careful of race conditions, like this one: Pull the reader lock on the shared class, check you answer - let's say that it is a better answer, drop the reader lock and pull the writer lock and update the shared class. The problem here is that another thread could have updated the class while you were waiting for the writer lock and you just blew away the "best" answer without checking it once you have the writer lock.

Have fun.

Karl Strings
Hi Karl, thanks for the response. One of the things I liked about TPL is the fact that it scales up with CPU's and what's going on in the system automatically. Saving me from having to monitor thread performance etc and adjust my numbers of threads accordingly. I've managed to work out quite a bit previously, just one of those problems it's difficult to keep all in your head and don't want to introduce threading issues.
Ian
I am not sure why you think you need so much overhead on the threads. There is no need to monitor performance or anything, just let them go until there are no more elements in the queue and they exit. You can wait for them to close by waiting for them to join.for( int i = 0; i = Environment.ProcessorCount; i++ ) { ... create your threads and add them to a list ... }ThreadList.ForEach( T => { T.Join(); } );I think you are over-complicating this. TPL would be like cracking a walnut with a jackhammer. But in the end, you need to pick your own poision =)
Karl Strings
I disagree. The code you have above is less than ideal. You probably want 2-3x the number of threads as tasks to hide latencies. It also doesn't account for other loading on the machine other than your application. The TPL's default scheduler will deal with both these cases. I'd really suggest taking a serious look at what it does before saying that it's over complicated.
Ade Miller
1) Neither of us knows what is ideal, that is for the dev to decide. 2) More threads than tasks will not hide anything. 3) I never said the TPL was over complicated and you don't know if I have taken a serious look at the TPL or not. 4) I said threading was complicated. The TPL is not a panacea, it is just another tool in the box. It has its place, its purpose, and its own set of strengths, drawbacks, and complexities. 5) Give the dev something useable rather than just being disagreeable and posting fluff.
Karl Strings
Karl, I think something that actually makes a difference, which I'll update the question with a bit later is that there is no certain end time. Threads keep running until a specified timeout is hit as it is a heuristic based solver. So you want to get as much done in the time period you've been given as possible.
Ian
Give the TPL a shot. I have been working with threaded code in a production server environment on a daily basis for 5 years, so rolling my own threaded solution seems so natural. Some of our code is scheduled to port to TPL, some is not. If you find that rolling your own is too complicated, and it really is complicated, you may have better luck with the TPL. In the end you will get to play with a very powerful new tech. Whether one solution is better than the other, that is for you to decide.
Karl Strings
TYPO: "You probably want 2-3x the number of threads as tasks to hide latencies..." Should read "You probably want 2-3x the number of threads than cores/hardware threads (ProcessorCount) to hide latencies (I/O, cache misses etc)."
Ade Miller
+3  A: 

I would definitely look at the TPL. It allows you to abstract your problem. You can think about tasks and how they do work and share data, rather than spending as much time on the underlying thread model and creating your wn threads and managing them. The TPL will allow you to create tasks which it assigns to a thread pool. The TPL then manages the pool and will adjust the number of running tasks to maximize performance. It will do this on a variety of hardware configurations (cores) which makes it easier to develop and application which will not need a major rewrite when moving between different hardware.

There's still a lot you have to think about, especially around sharing state. The the TPL is usually a better approach than rolling your own unless you are very experienced with threading and/or have some special case application which the TPL is poorly suited.

1.They need to be initalized with a different 'optimization metric'. In other words they are attempting to optimize different things, with a precedence level set within code. This means they all run slightly different calculation engines. I'm not sure if I can do this with the TPL..

You can do this by creating tasks and passing them different starting conditions.

2.If one of the threads finds a better solution that the currently best known solution (which needs to be shared across all threads) then it needs to update the best solution, and force a number of other threads to restart (again this depends on precedence levels of the optimization metrics).

It is possible to cancel tasks and start new ones.

3.I may also wish to combine certain calculations across threads (e.g. keep a union of probabilities for a certain approach to the problem). This is probably more optional though.

Not sure I understand this requirement.

4.The whole system needs to be thread safe obviously and I want it to be running as fast as possible.

Even with the TPL is you share data across tasks (threads) then this still your responsibility to do this in a threadsafe way. However, the TPL comes with several threadsafe classes for queue, collection, bag etc.

From the sounds of it this a variant of the master/worker pattern with some speculative execution and work stealing thrown in. You can find more details on this and other patterns at http://parallelpatterns.codeplex.com/ there's a link at the bottom of the page to a white paper by Stephen Toub covering additional details too.

Ade Miller