Multithreading and performance

J

Jurgen

Hello,

I've a C# program that:
1) loads data for 30000 items from SQL Server
2) loops through all the items and does some extensive calculaltions on the data
3) loops through all the items to Writs the resutls back to the DB
This takes about half an hour, almost equally divided between step 2 and step1+3. The program runs
on the same machine as the SQL Server.
So I have 1 CPU intensive step and 2 disc I/O intensive steps.
I've never used threads before, but I've been thinking about using threading to improve
performance. A typical thread would load the data for a single article, perform the arithmetics
and write back the results. This way I hope to keep the processor calculating for an item while
disc operations are being performed for other items.
IS this feasable/easy to achieve and will this be faster than my current program?

regards,
 
M

Miha Markic [MVP C#]

Hi Jurgen,

I would create three threads - for each step one thread.
They would act like a pipeline:
1. thread is loading messages into a queue
2. when new message arrive in queue it is removed from calculation queue and
calculation is done. Message is put in writeback queue.
3. when result arrives in writeback queue it is removed from queue and saved
to database
Something like that.
 
S

Simon Watson

Jurgen said:
Hello,

I've a C# program that:
1) loads data for 30000 items from SQL Server
2) loops through all the items and does some extensive calculaltions on the data
3) loops through all the items to Writs the resutls back to the DB
This takes about half an hour, almost equally divided between step 2 and step1+3. The program runs
on the same machine as the SQL Server.
So I have 1 CPU intensive step and 2 disc I/O intensive steps.
I've never used threads before, but I've been thinking about using threading to improve
performance. A typical thread would load the data for a single article, perform the arithmetics
and write back the results. This way I hope to keep the processor calculating for an item while
disc operations are being performed for other items.
IS this feasable/easy to achieve and will this be faster than my current program?

regards,

Jurgen,

I would agree with the other posters, use one thread to read/write records
(in blocks, not all at once) into/from a queue.

When it comes to the processing, I'd use a thread pool, with the number of
threads in the pool based on the number of logical processors on the local
machine. That way, if the app is run on an MP box (and with multicore
getting popular, that's pretty likely) you can take advantage of it without
having to re-write the app.

You'd need to do some profiling to come up with the optimal number of
threads per processor. My first instinct would be two, so that there's
always be something running on each logical processor.

Simon
 
M

Miha Markic [MVP C#]

When it comes to the processing, I'd use a thread pool, with the number of
threads in the pool based on the number of logical processors on the local
machine. That way, if the app is run on an MP box (and with multicore
getting popular, that's pretty likely) you can take advantage of it
without
having to re-write the app.

Right, multiprocessing, I have to correct myself - I would use number of
threads for calculating = number of cores.
If you use one thread/core it might yield you better performance than thread
pool however you might have problems setting thread affinities.
 
J

Jurgen

Miha Markic [MVP C#] wrote:

Right, multiprocessing, I have to correct myself - I would use number of threads for calculating
= number of cores. If you use one thread/core it might yield you better performance than thread
pool however you might have problems setting thread affinities.

first of all, thank you all very much for the help.
What i've done so far:
I created 3 threads:
thread 1 reads data and places objects on queue A (loop through all my DB records). If queue A is
full, the thread waits until space becomes available.
thread 2 picks (and removes) objects one by one from queue A, does the calculations and puts the
objects on queue B. If queue B is full, the thread waits until space becomes available. If queue A
is empty, the thread waits until objects become available.
thread 3 picks (and removes) objects from queue B and writes the results to the DB.
This gives me a reduction of 25% in processing time! (not bad for half a day of work, with zero
background on threading ;) )

So what you suggest is to replace thread 2 with a number of threads (depending on # CPU's)?
Do you have comments on the method i've used?

Simon,
You suggest to use one thread (where I use thread 1 and 3) to read AND write my data, and do this
in blocks instead of all at once (i put do a Thread.Sleep(x) every 1000 records?) . Can you
elaborate a bit more, because it's not quiet clear to me .
 
M

Miha Markic [MVP C#]

Hi Jurgen,

Jurgen said:
Miha Markic [MVP C#] wrote:

Right, multiprocessing, I have to correct myself - I would use number of
threads for calculating
= number of cores. If you use one thread/core it might yield you better
performance than thread
pool however you might have problems setting thread affinities.

first of all, thank you all very much for the help.
What i've done so far:
I created 3 threads:
thread 1 reads data and places objects on queue A (loop through all my DB
records). If queue A is
full, the thread waits until space becomes available.

Why do you limit the queue size?
thread 2 picks (and removes) objects one by one from queue A, does the
calculations and puts the
objects on queue B. If queue B is full, the thread waits until space
becomes available. If queue A
is empty, the thread waits until objects become available.
thread 3 picks (and removes) objects from queue B and writes the results
to the DB.
This gives me a reduction of 25% in processing time! (not bad for half a
day of work, with zero
background on threading ;) )
Great.


So what you suggest is to replace thread 2 with a number of threads
(depending on # CPU's)?

Yes, actually to the number of cores (not that some CPUs have two or more
cores in a single chip).
Do you have comments on the method i've used?

Apart from the limiting queue size not.
It might be interesting to find the bottleneck - IOW which thread is slowing
down the process. If it is calculation thread then spawning more threads
(assuming you have multi CPU machine) will help big time. If IO thread is
bottleneck then there is not much you can do to speed up the process.
 
J

Jurgen

Miha said:
Why do you limit the queue size?
In fact I use a static length array. I realize now that eg using the Queue class would be more
appropiate.
It might be interesting to find the bottleneck
both the calculations and I/O take some time, but because the number crunching starts while data
is still loading gives me the performance improvement. In fact, eliminating thread 3 and putting
the write operations in thread 2 gives me more or less the same result as using 3 threads.
So multithreading the calculations won't give a big difference on a sigle CPU-single core system I
understand. Do you know how can I retrieve the numbre of cores of a system?

I realize that multithreading can be a very powerful method of speeding up things, to bad I never
paid it much interest. It seemed a bit too 'scary', but once you get working with it, it isn't that
bad.
 
W

William Stacey [MVP]

I would use a bounded blocking (one lock) queue. That way you get automatic
blocking when queue is empty/full and producers/consumers can catch up. I
have one on the CodeProject.
 
S

Simon Watson

Jurgen said:
Miha Markic [MVP C#] wrote:

Right, multiprocessing, I have to correct myself - I would use number of threads for calculating
= number of cores. If you use one thread/core it might yield you better performance than thread
pool however you might have problems setting thread affinities.

first of all, thank you all very much for the help.
What i've done so far:
I created 3 threads:
thread 1 reads data and places objects on queue A (loop through all my DB records). If queue A is
full, the thread waits until space becomes available.
thread 2 picks (and removes) objects one by one from queue A, does the calculations and puts the
objects on queue B. If queue B is full, the thread waits until space becomes available. If queue A
is empty, the thread waits until objects become available.
thread 3 picks (and removes) objects from queue B and writes the results to the DB.
This gives me a reduction of 25% in processing time! (not bad for half a day of work, with zero
background on threading ;) )

So what you suggest is to replace thread 2 with a number of threads (depending on # CPU's)?
Do you have comments on the method i've used?

Simon,
You suggest to use one thread (where I use thread 1 and 3) to read AND write my data, and do this
in blocks instead of all at once (i put do a Thread.Sleep(x) every 1000 records?) . Can you
elaborate a bit more, because it's not quiet clear to me .

Jurgen,

Sorry, I guess I wasn't too clear. I meant one thread for reading and one
for writing, as you've done.

Simon
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top