I don't think you need a custom thread pool, especially if you're doing a lot parallel I/O which naturally uses IOCP threads. This applies to any other API which only acquires a thread from the pool when its task has completed (e.g, Task.Delay
).
Usually you do await task.ConfigureAwait(false)
for continuation to happen on the same thread the task
has completed on:
// non-IOCP (worker) continuation thread
await Task.Delay(1000).ConfigureAwait(false);
// IOCP continuation thread
await stream.ReadAsync(buff, 0, buff.Length).ConfigureAwait(false);
Now, in ASP.NET you don't even need to use ConfigureAwait
. ASP.NET's AspNetSynchronizationContext
doesn't maintain thread affinity for await
continuations, unlike WinFormsSynchronizationContext
or DispatcherSynchronizationContext
do for a UI app. Your continuations will run on whatever thread the task has completed on, as is. AspNetSynchronizationContext
just "enters" the ASP.NET context on that thread, to make sure your code has access to HttpContext
and other relevant ASP.NET request ambient state information.
You can increase the default number of IOCP and worker threads with ThreadPool.SetMinThreads
to account for ThreadPool
stuttering problems.
If your only reason for custom thread pool is to limit the level of parallelism for your tasks, use TPL Dataflow or simply SemaphoreSlim.WaitAsync
(check "Throttling asynchronous tasks").
That said, you can have a very precise control over the Task
continuation if you implement a custom awaiter. Check this question for a basic example of that.