After reading various MSDN articles, tutorials, and posts on here I came up with a design for a windows service that I wanted to make sure my threading strategy is proper and won't lead to memory, cpu, database issues.
Here is the basic flow.
MAIN THREAD
- Collect list of service to be loaded.
- Loads each service.
SERVICE THREAD (started by timer event on step 3)
- Start Service
- Setup Timer - Setup so there is no overlapping, only 1 processing call can be made.
- Processing method
- Makes database call to get information which is a list of
Commands
. - Gathers a collection of
Handlers
. - Does a
Parallel.ForEach()
over the list ofCommands
. - Immediately does a normal
foreach()
over theHandlers
- Makes database call to get information which is a list of
COMMAND THREADS
- Command does a normal
foreach()
over theHandlers
passing in theCommand
. - Each
Handler
executes code that may CRUD the database or reach out to various other services.- Due to the
Parallel.ForEach()
I am spinning up 1 new thread perCommand
. - There could be 1000+
- Since each
Command
has multipleHandlers
theseHandlers
will run on the same thread as theCommand
. - This is to prevent database clashes since each
Handler
will be working with the same set of data. - This is to make each
Command
wait on its ownHandler
threads.
- Due to the
WAIT POINTS
- Service waits for all
Commands
to finish executing before firing another round of round of commands. Commands
wait for allHandlers
to to finish.Handlers
wait for one to finish before moving onto the next.
PERFORMANCE
- 3000x FOREACH Console.WriteLine() avg. 160ms
- 3000x FORALL Console.WriteLine() avg. 275ms
- 3000x FOREACH DatabaseCallAsync() avg. 1200ms
- 3000x FORALL DatabaseCallAsync() avg. 600ms
Interesting how the normal foreach was faster with just the WriteLine() but twice as slow with the database call. I still have concern about competing for resources with the other services.
QUESTIONS
- Do you recognize any immediate issues with this design?
- Do you have any suggestions that would make it more efficient with resources and speed?
- I am noticing extremely high CPU usage on all cores when running just
Console.WriteLines()
in the actual execution point, should I be limiting the threads?- I noticed when I used a normal
foreach()
it still had pretty high cpu usage but had more resting points, I still need to put a counter in there to see how many calls are actually being made for each to see which is actually processing more but right now I am just concerned with the high usage.
- I noticed when I used a normal
Parallel.ForEach
will block until all commands are processed. You gain nothing over plain Tasks or Dataflow ActionBlocks, but you do waste ThreadPool threads for long-running tasks