-
Notifications
You must be signed in to change notification settings - Fork 16
Sync Async
PowerThreadPool natively supports both synchronous and asynchronous tasks, enabling seamless mixing of sync and async tasks. It provides consistent lifecycle control and result retrieval mechanisms for both synchronous and asynchronous tasks.
PowerThreadPool allows various ways to submit synchronous tasks using the QueueWorkItem function, including parameterless/parameterized Action, Func, and supports generic parameters and return values.
powerPool.QueueWorkItem(() =>
{
Thread.Sleep(1000);
});PowerThreadPool natively supports asynchronous tasks of type Task or Task<TResult>, which can be submitted via the QueueWorkItem function.
powerPool.QueueWorkItem(async () =>
{
await Task.Delay(1000);
});
PowerThreadPool can bring asynchronous tasks under the same unified management system as synchronous tasks, including scheduling, waiting, grouping, result collection, cancellation, pausing, resuming, and exception handling. This greatly simplifies the complexity of multithreading and async scenarios in .NET, allowing developers to focus on business logic without worrying about async details.
The capabilities of asynchronous tasks remain consistent with those of synchronous tasks. PowerThreadPool’s unified management of asynchronous tasks does not compromise the essential characteristics of asynchrony; instead, it brings their scheduling and lifecycle under unified thread pool management, achieving "unified entry and unified control."
Under this unified management, async operations still preserve their thread-independent nature: they release the Worker while awaiting incomplete operations and are not converted into long-running blocking Worker executions.
What PTP essentially does is treat async continuations as Work units as well, bringing them back under PTP’s scheduling, control, and statistics system. This enables tasks to benefit from features like pause, stop, etc., and ensures WorkOption configurations continue to apply to each managed continuation in an async task.
Example 1. Settings in WorkOption:
With PTP, a task as a whole can be governed by priority and be scheduled correctly.
If you simply wrap logic with Task, you are usually forced to choose between two unsatisfactory strategies:
- "Priority only affects the start": this is the most common naive wrapper, where priority only determines the start order of async tasks, but does not affect the execution order of their continuations.
-
"Lower priority tasks cannot run until all higher priority tasks finish": during this time, even if higher priority tasks are awaiting I/O and there are free thread slots, lower priority tasks still cannot interleave. This wastes resources and hurts the concurrency benefits of
async.
Example 2. Control primitives:
Control APIs like PauseIfRequested and StopIfRequested, which require the current Worker context, are generally expected to be called from within a PTP worker.
For example, PauseIfRequested will throw an InvalidOperationException if the current Worker cannot be obtained.
// Directly get current thread worker since it is guaranteed to exist
// If not, just let Work execute failed
if (!GetCurrentThreadWorker(out worker))
{
throw new InvalidOperationException("PauseIfRequested must be called on a PowerPool worker thread.");
}By managing continuations, users can call these primitives anywhere inside their async tasks, without having to wonder why calling PauseIfRequested inside the function passed to QueueWorkItem results in an InvalidOperationException.
Example 3. Execution time statistics:
Once an async task is split into multiple segments that each run on a Worker, PTP can accumulate the actual CPU time spent by these segments on the Worker, rather than including the time spent awaiting external I/O.
This allows both async and sync tasks to use the same ExecuteResult / WorkEndedEventArgs to inspect execution statistics, while still preserving the async behavior of not occupying threads while waiting on I/O.
Although third party code does not rely on PTP’s advanced features, the standard in the .NET ecosystem is still to use CancellationToken for basic control and management. In other words, passing a CancellationToken when calling third party code is both common and often necessary.
For third party libraries that do not use ConfigureAwait(false): Although we cannot change their internal logic, PTP by default inserts interruption checks between continuations, so Stop(...) will still be honored when execution reaches an await. Of course, you can also use the overload that accepts a CancellationToken and pass that token through to the third party library to extend the control scope.
For third party libraries that do use ConfigureAwait(false):
-
If you need control: You can use the overload that accepts a
CancellationTokenand pass it through to the third party library. When you call a pool wideStop, or callStopwith the current Work’s id as a parameter, the notification will be correctly propagated to thisCancellationToken. - If you don’t need control: You can simply leave it as is. PTP does not directly manage the continuations of such third party code, and the third party library itself does not depend on PTP’s advanced features, so it does not need to be managed.
Whether or not the third party library uses ConfigureAwait(false) only affects whether continuations inside that library go through the PTP context.
Regardless of what happens inside the third party library, the continuation after the entry await will flow back to a PTP Worker. Therefore, you can still correctly use PTP features in these post entry continuations.
Exception: If your own code calls ConfigureAwait(false), then escaping PTP’s control is inevitable. Before explicitly calling it, you should be fully aware of the consequences; the rest of this document follows the same principle.
PowerThreadPool supports mixing synchronous and asynchronous tasks for unified management. For example:
powerPool.QueueWorkItem(() => {/* synchronous task */});
powerPool.QueueWorkItem(async () => {/* asynchronous task */});All tasks can be paused, resumed, canceled, grouped, and have their results collected through a consistent interface.
- Sync | Async
- Pool Control | Work Control
- Divide And Conquer
- Thread Pool Sizing
- Work Callback | Default Callback
- Rejection Policy
- Parallel Execution
- Work Priority | Thread Priority
- Error Handling
- Work Timeout | Cumulative Work Timeout
- Work Dependency
- Work Group
- Events
- Runtime Status
- Running Timer
- Queue Type (FIFO | LIFO | Deque | Custom)
Core
Results
Options