0
# Threadpoolctl
1
2
Python helpers to limit the number of threads used in threadpool-backed native libraries for scientific computing and data science (e.g. BLAS and OpenMP). Fine control of underlying thread-pool sizes helps mitigate oversubscription issues in workloads involving nested parallelism.
3
4
## Package Information
5
6
- **Package Name**: threadpoolctl
7
- **Language**: Python
8
- **Installation**: `pip install threadpoolctl`
9
10
## Core Imports
11
12
```python
13
from threadpoolctl import threadpool_info, threadpool_limits, ThreadpoolController
14
```
15
16
For library controller registration:
17
18
```python
19
from threadpoolctl import LibController, register
20
```
21
22
## Basic Usage
23
24
```python
25
from threadpoolctl import threadpool_info, threadpool_limits
26
27
# Inspect current thread pool state
28
info = threadpool_info()
29
print(f"Found {len(info)} libraries with thread pools")
30
31
# Limit threads temporarily with context manager
32
with threadpool_limits(limits=1):
33
# All thread pools limited to 1 thread
34
# Your computation here
35
pass
36
37
# Limit specific API types
38
with threadpool_limits(limits=2, user_api='blas'):
39
# Only BLAS libraries limited to 2 threads
40
# Your computation here
41
pass
42
43
# Use as decorator
44
@threadpool_limits(limits=1)
45
def compute():
46
# Function runs with thread pools limited to 1 thread
47
pass
48
```
49
50
## Architecture
51
52
Threadpoolctl's architecture centers around **Library Controllers** that manage specific thread pool implementations:
53
54
- **ThreadpoolController**: Main controller that discovers and manages all loaded thread pool libraries
55
- **LibController**: Abstract base class for individual library controllers
56
- **Concrete Controllers**: Specific implementations for OpenBLAS, MKL, BLIS, FlexiBLAS, and OpenMP
57
- **Thread Limiters**: Context managers and decorators for temporarily changing thread limits
58
59
The library automatically detects loaded scientific computing libraries and provides a unified interface for thread pool control across different implementations.
60
61
## Capabilities
62
63
### Thread Pool Introspection
64
65
Discover and inspect thread pool libraries currently loaded in the Python process, returning detailed information about each library including version, thread count, and implementation details.
66
67
```python { .api }
68
def threadpool_info() -> list[dict[str, Any]]:
69
"""
70
Return thread pool information for all detected libraries.
71
72
Scans loaded shared libraries and returns information for supported
73
thread pool libraries (BLAS implementations and OpenMP runtimes).
74
75
Returns:
76
list[dict[str, Any]]: List of library info dictionaries with keys:
77
- user_api: str ('blas', 'openmp')
78
- internal_api: str ('openblas', 'mkl', 'blis', 'flexiblas', 'openmp')
79
- prefix: str (library filename prefix)
80
- filepath: str (path to loaded shared library)
81
- version: str | None (library version if available)
82
- num_threads: int (current thread limit)
83
- Additional implementation-specific attributes
84
"""
85
```
86
87
[Thread Pool Introspection](./introspection.md)
88
89
### Thread Limiting
90
91
Temporarily limit the number of threads used by thread pool libraries using context managers or decorators, with support for global limits, per-API limits, or per-library limits.
92
93
```python { .api }
94
class threadpool_limits:
95
"""
96
Context manager/decorator for limiting thread pool sizes.
97
98
Can be used as callable, context manager, or decorator.
99
100
Args:
101
limits: int | dict[str, int] | str | None
102
- int: Global thread limit for all libraries
103
- dict: Per-API or per-library limits {api/prefix: limit}
104
- 'sequential_blas_under_openmp': Special case for nested parallelism
105
- None: No limits applied
106
user_api: str | None ('blas', 'openmp', None)
107
API type to limit when limits is int
108
"""
109
110
def __init__(self, limits=None, user_api=None): ...
111
112
def __enter__(self) -> 'threadpool_limits':
113
"""Enter context manager, returns self."""
114
115
def __exit__(self, type, value, traceback) -> None:
116
"""Exit context manager, restores original limits."""
117
118
def restore_original_limits(self) -> None:
119
"""Manually restore original thread limits."""
120
121
def unregister(self) -> None:
122
"""Alias for restore_original_limits() (backward compatibility)."""
123
124
def get_original_num_threads(self) -> dict[str, int]:
125
"""
126
Get original thread counts before limiting.
127
128
Returns:
129
dict[str, int]: Original thread counts by user_api
130
"""
131
132
@classmethod
133
def wrap(cls, limits=None, user_api=None) -> 'Callable':
134
"""
135
Create decorator version that delays limit setting.
136
137
Returns:
138
Callable: Decorator function for use with @threadpool_limits.wrap(...)
139
"""
140
```
141
142
[Thread Limiting](./limiting.md)
143
144
### Advanced Thread Pool Control
145
146
Programmatic control of thread pools with library selection, filtering, and advanced limiting patterns for complex scientific computing workloads.
147
148
```python { .api }
149
class ThreadpoolController:
150
"""
151
Controller for all loaded supported thread pool libraries.
152
153
Automatically discovers supported libraries when instantiated and provides
154
methods for filtering, selecting, and controlling their thread settings.
155
156
Attributes:
157
lib_controllers: list[LibController] - Individual library controllers
158
"""
159
160
def __init__(self):
161
"""Initialize controller and discover loaded libraries."""
162
163
def info(self) -> list[dict[str, Any]]:
164
"""
165
Get information about all controlled libraries.
166
167
Returns:
168
list[dict[str, Any]]: List of library info dicts
169
"""
170
171
def select(self, **kwargs) -> 'ThreadpoolController':
172
"""
173
Filter libraries by attributes.
174
175
Args:
176
**kwargs: Attribute filters where key is attribute name and value
177
is either a single value or list of acceptable values.
178
179
Returns:
180
ThreadpoolController: New controller with filtered library subset
181
"""
182
183
def limit(self, *, limits=None, user_api=None) -> '_ThreadpoolLimiter':
184
"""
185
Create thread limiter for this controller's libraries.
186
187
Args:
188
limits: int | dict[str, int] | str | None - Thread limit specification
189
user_api: str | None - API type filter
190
191
Returns:
192
_ThreadpoolLimiter: Context manager for temporary limiting
193
"""
194
195
def wrap(self, *, limits=None, user_api=None) -> 'Callable':
196
"""
197
Create decorator for this controller's libraries.
198
199
Args:
200
limits: int | dict[str, int] | str | None - Thread limit specification
201
user_api: str | None - API type filter
202
203
Returns:
204
Callable: Decorator function for thread limiting
205
"""
206
207
def __len__(self) -> int:
208
"""
209
Number of controlled libraries.
210
211
Returns:
212
int: Count of lib_controllers
213
"""
214
```
215
216
[Advanced Control](./advanced-control.md)
217
218
### Custom Library Support
219
220
Extend threadpoolctl with custom library controllers for additional thread pool libraries not supported out of the box.
221
222
```python { .api }
223
class LibController:
224
"""
225
Abstract base class for individual library controllers.
226
227
Class Attributes:
228
user_api: str - Standardized API name ('blas', 'openmp', etc.)
229
internal_api: str - Implementation-specific identifier
230
filename_prefixes: tuple[str, ...] - Library filename prefixes to match
231
check_symbols: tuple[str, ...] - Optional symbol names to verify compatibility
232
"""
233
234
def __init__(self, *, filepath=None, prefix=None, parent=None):
235
"""
236
Initialize library controller.
237
238
Args:
239
filepath: str | None - Path to shared library file
240
prefix: str | None - Matched filename prefix
241
parent: ThreadpoolController | None - Parent controller instance
242
"""
243
244
def info(self) -> dict[str, Any]:
245
"""
246
Return library information dictionary.
247
248
Returns:
249
dict: Library info with standard keys plus additional attributes
250
"""
251
252
def get_num_threads(self) -> int | None:
253
"""
254
Get current maximum thread count (abstract method).
255
256
Returns:
257
int | None: Current thread limit, None if unavailable
258
"""
259
260
def set_num_threads(self, num_threads: int) -> Any:
261
"""
262
Set maximum thread count (abstract method).
263
264
Args:
265
num_threads: int - New thread limit
266
267
Returns:
268
Any: Implementation-specific return value
269
"""
270
271
def get_version(self) -> str | None:
272
"""
273
Get library version (abstract method).
274
275
Returns:
276
str | None: Version string, None if unavailable
277
"""
278
279
def set_additional_attributes(self) -> None:
280
"""
281
Set implementation-specific attributes.
282
283
Called during initialization to set custom attributes that will
284
be included in the info() dictionary.
285
"""
286
287
@property
288
def num_threads(self) -> int | None:
289
"""Current thread limit (dynamic property)."""
290
291
def register(controller: type[LibController]) -> None:
292
"""
293
Register a new library controller class.
294
295
Adds the controller to the global registry so it will be used
296
during library discovery in future ThreadpoolController instances.
297
298
Args:
299
controller: type[LibController] - LibController subclass to register
300
"""
301
```
302
303
[Custom Library Support](./custom-libraries.md)
304
305
## Command Line Interface
306
307
Threadpoolctl provides a command-line interface to inspect thread pool libraries loaded by Python packages.
308
309
```bash { .api }
310
# Basic usage
311
python -m threadpoolctl
312
313
# Import specific modules before introspection
314
python -m threadpoolctl -i numpy scipy.linalg xgboost
315
316
# Execute Python code before introspection
317
python -m threadpoolctl -c "import sklearn; from sklearn.ensemble import RandomForestClassifier"
318
319
# Combined usage
320
python -m threadpoolctl -i numpy -c "import threading; print(f'Python threads: {threading.active_count()}')"
321
```
322
323
**Arguments:**
324
- `-i, --import MODULE [MODULE ...]`: Import Python modules before introspecting thread pools
325
- `-c, --command COMMAND`: Execute Python statement before introspecting thread pools
326
327
**Output:** JSON-formatted list of thread pool library information written to stdout. Warning messages for missing modules are written to stderr.
328
329
**Example Output:**
330
```json
331
[
332
{
333
"filepath": "/usr/lib/libmkl_rt.so",
334
"prefix": "libmkl_rt",
335
"user_api": "blas",
336
"internal_api": "mkl",
337
"version": "2019.0.4",
338
"num_threads": 2,
339
"threading_layer": "intel"
340
}
341
]
342
```
343
344
## Types
345
346
```python { .api }
347
# Library information dictionary structure
348
LibraryInfo = dict[str, Any] # Keys: user_api, internal_api, prefix, filepath, version, num_threads, ...
349
350
# Thread limit specifications
351
ThreadLimits = int | dict[str, int] | str | None
352
353
# API type specifications
354
UserAPI = Literal["blas", "openmp"] | None
355
```