After spending years trying to be fancy and calculating how many items I
should be doing in parallel, I take a simpler approach now.
I use a value, that's defined in my app.config.
"SimultaniousProcessingLimit". I generally set this to a value of 10. I
have no good reason for this, and can't defend the number at all, but
that's where I start. If an installation needs more parallelism, then I
bump the number. If it's a small install, I leave it at 10.
Getting fancy (or worse, adaptive!), seems to cause more problems than
it solves. Just make the value easily configurable.
... besides, when you're debugging, it's really nice to be able to set
the value to "1" or "2". This makes everything easier, and also helps
you write edge case tests.
--
Chris Mullins
Chris,
Thanks for the design suggestion of tracking a counter from a dedicated
thread. Since the System.ThreadPool is used by more than just the 3rd
party lib, should the limit be set to some percentage of the max num of
System.ThreadPool threads? That way, the 3rd party lib I'm using won't
hog all of them. If so, does 50% sound reasonable?
A question about ThreadPool.GetMaxThreads: It returns two counts,
workerThreads and completionPortThreads. The second count,
completionPortThreads, that's not referring to the count of the IOCP
thread pool, is it?
If not, should the limit be based on the sum of workerThreads +
completionPortThreads or just workerThreads?
Thanks for your help and your blog articles.
Marc
The author of that blog article is very smart, and really knows his
stuff. I'm sure he's right!
(Yes, that's a feeble attempt at
humor...)
If you take lots and lots of operations off the IOCP TP and dump them
into a 3rd party app that uses a naieve async infrastructure (such as
the System ThreadPool), then you're application is going to grind to a
screeching hault. The Threadpool is pretty big these days (250 threads
per processor core, by default), but you really don't want that many
threads running at once.
If you start blocking IOCP threads, you're going to cause all sorts of
problems - you'll fill up your Windows Socket buffers, and the IOCP
thread pool will have stutter problems, etc. You really want to avoid
this if you can.
Your best bet is likley to queue things up as they come off the IOCP
thread pool. Then have a single dedicated thread for taking items from
your queue and handing them to the library. In this thread you can
track a counter "how many items processing right now?", and if you're
at or near your limit, then don't don't dequeue the item from your
queue quite yet. The drawback to this is that you'll have at least 2
context switches per operation - once onto your "worker" thread, and
another into the actual Thread Pool thread the library uses. If this
becomes a problem, you could (later, after it all works - don't do
premature optimization!) probably have your IOCP thread check the
limit counter, and directly post the item to the 3rd party library,
thereby cutting out one of the context switches. This isn't a huge
penalty to pay, although minimizing this in the general case would be
nice.
(Be sure to look at some of the Parallel Datastructures that Joe Duffy
wrote about in his MSDN article a few months back. Several of those
were related to multi-threaded queue management...)
Just try really hard to avoid stalling the IOCP threads on a regular
basis and/or for long periods of time, as this will cause poor general
behavior.
--
Chris Mullins
On Thu, 17 Jan 2008 13:50:44 -0800, Marc Sherman
Hello,
I'm designing an async socket server and I've read that the IOCP
thread pool
can overwhelm the System.ThreadPool. I'm thinking about throttling
the IOCP
threads by only allowing up to MAX connections to be accepted at
any given
time where MAX is less than the number of threads in the
System.ThreadPool.
[...]
Does this sound reasonable?
No.
First of all, there is a separate IOCP thread pool. IOCP operations
aren't going to use the regular thread pool at all, never mind
overwhelm it. I don't know where you read what you read, but it's
wrong.
I should have mentioned that from the IOCP thread I'll be calling 3rd
party code that does use the System.ThreadPool to support it's own
async operations. The article I read is
http://www.coversant.net/Coversant/Blogs/tabid/88/EntryID/8/Default.aspx.
Basically, our server will have the same architecture as "SoapBox
Server, Stage 1" as described in
http://www.coversant.net/Coversant/Blogs/tabid/88/EntryID/10/Default.aspx
with the difference being that we'll be using the System.Threapool,
not a custom threadpool as the author shows.
In the first article, the author mentions that their solution to
overwhelming the System.ThreadPool was to roll their own threadpool
which is something I don't want to do at this point.
Marc