0
# Advanced Thread Pool Control
1
2
Programmatic control of thread pools with library selection, filtering, and advanced limiting patterns. The ThreadpoolController provides fine-grained control over individual libraries and their thread settings.
3
4
## Capabilities
5
6
### ThreadpoolController
7
8
Main controller class that discovers and manages all loaded thread pool libraries.
9
10
```python { .api }
11
class ThreadpoolController:
12
"""
13
Controller for all loaded supported thread pool libraries.
14
15
Automatically discovers supported libraries when instantiated and provides
16
methods for filtering, selecting, and controlling their thread settings.
17
18
Attributes:
19
lib_controllers: list[LibController]
20
List of individual library controller instances
21
"""
22
23
def __init__(self):
24
"""
25
Initialize controller and discover loaded libraries.
26
27
Scans system for loaded shared libraries and creates controllers
28
for supported thread pool libraries (BLAS and OpenMP implementations).
29
"""
30
31
def info(self):
32
"""
33
Get information about all controlled libraries.
34
35
Returns:
36
list[dict]: List of library info dicts (same format as threadpool_info())
37
"""
38
39
def select(self, **kwargs):
40
"""
41
Filter libraries by attributes.
42
43
Args:
44
**kwargs: Attribute filters where key is attribute name and value
45
is either a single value or list of acceptable values.
46
Common keys: user_api, internal_api, prefix, version, etc.
47
48
Returns:
49
ThreadpoolController: New controller with filtered library subset
50
"""
51
52
def limit(self, *, limits=None, user_api=None):
53
"""
54
Create thread limiter for this controller's libraries.
55
56
Args:
57
limits: int | dict | str | None - Thread limit specification
58
user_api: str | None - API type filter
59
60
Returns:
61
_ThreadpoolLimiter: Context manager for temporary limiting
62
"""
63
64
def wrap(self, *, limits=None, user_api=None):
65
"""
66
Create decorator for this controller's libraries.
67
68
Args:
69
limits: int | dict | str | None - Thread limit specification
70
user_api: str | None - API type filter
71
72
Returns:
73
Decorator function for thread limiting
74
"""
75
76
def __len__(self):
77
"""
78
Number of controlled libraries.
79
80
Returns:
81
int: Count of lib_controllers
82
"""
83
```
84
85
### Library Selection and Filtering
86
87
```python
88
from threadpoolctl import ThreadpoolController
89
90
# Create controller
91
controller = ThreadpoolController()
92
print(f"Found {len(controller)} thread pool libraries")
93
94
# Select by API type
95
blas_controller = controller.select(user_api='blas')
96
openmp_controller = controller.select(user_api='openmp')
97
98
# Select by implementation
99
openblas_controller = controller.select(internal_api='openblas')
100
mkl_controller = controller.select(internal_api='mkl')
101
102
# Select by multiple criteria (OR logic)
103
specific_controller = controller.select(
104
internal_api=['openblas', 'mkl'],
105
prefix='libmkl_rt'
106
)
107
108
# Select by custom attributes (for libraries that have them)
109
openmp_blas = controller.select(threading_layer='openmp')
110
```
111
112
### Advanced Limiting with Controllers
113
114
```python
115
from threadpoolctl import ThreadpoolController
116
117
controller = ThreadpoolController()
118
119
# Limit only BLAS libraries to 1 thread
120
blas_controller = controller.select(user_api='blas')
121
with blas_controller.limit(limits=1):
122
# Only BLAS libraries limited, OpenMP unchanged
123
result = numpy_computation()
124
125
# Different limits for different implementations
126
openblas_controller = controller.select(internal_api='openblas')
127
mkl_controller = controller.select(internal_api='mkl')
128
129
with openblas_controller.limit(limits=1):
130
with mkl_controller.limit(limits=2):
131
# OpenBLAS: 1 thread, MKL: 2 threads
132
result = mixed_blas_computation()
133
134
# Complex filtering and limiting
135
high_thread_controller = controller.select(
136
**{lib.prefix: lib.num_threads for lib in controller.lib_controllers
137
if lib.num_threads > 4}
138
)
139
with high_thread_controller.limit(limits=2):
140
# Only libraries with >4 threads are limited to 2
141
result = computation()
142
```
143
144
### Individual Library Controller Access
145
146
```python
147
from threadpoolctl import ThreadpoolController
148
149
controller = ThreadpoolController()
150
151
# Access individual library controllers
152
for lib_controller in controller.lib_controllers:
153
print(f"Library: {lib_controller.internal_api}")
154
print(f" Current threads: {lib_controller.num_threads}")
155
print(f" Prefix: {lib_controller.prefix}")
156
print(f" Version: {lib_controller.version}")
157
158
# Get full info dict
159
info = lib_controller.info()
160
print(f" Full info: {info}")
161
```
162
163
### FlexiBLAS Backend Management
164
165
For FlexiBLAS libraries, additional backend switching capabilities are available:
166
167
```python { .api }
168
# FlexiBLAS-specific method available on FlexiBLAS controller instances
169
def switch_backend(self, backend):
170
"""
171
Switch the FlexiBLAS backend.
172
173
Args:
174
backend: str - Backend name or path to shared library.
175
If not loaded, will be loaded first.
176
177
Raises:
178
RuntimeError: If backend loading or switching fails
179
"""
180
```
181
182
```python
183
from threadpoolctl import ThreadpoolController
184
185
controller = ThreadpoolController()
186
flexiblas_controller = controller.select(internal_api='flexiblas')
187
188
if flexiblas_controller:
189
flex_lib = flexiblas_controller.lib_controllers[0] # Get first FlexiBLAS instance
190
191
print(f"Available backends: {flex_lib.available_backends}")
192
print(f"Loaded backends: {flex_lib.loaded_backends}")
193
print(f"Current backend: {flex_lib.current_backend}")
194
195
# Switch to different backend
196
if 'OPENBLAS' in flex_lib.available_backends:
197
flex_lib.switch_backend('OPENBLAS')
198
print(f"Switched to: {flex_lib.current_backend}")
199
```
200
201
### Controller Composition Patterns
202
203
```python
204
from threadpoolctl import ThreadpoolController
205
206
# Create specialized controllers for different use cases
207
def create_compute_controller():
208
"""Controller optimized for compute workloads."""
209
controller = ThreadpoolController()
210
return controller.select(user_api='blas')
211
212
def create_parallel_controller():
213
"""Controller for parallel processing workloads."""
214
controller = ThreadpoolController()
215
return controller.select(user_api='openmp')
216
217
# Use in context
218
compute_controller = create_compute_controller()
219
parallel_controller = create_parallel_controller()
220
221
with compute_controller.limit(limits=1):
222
with parallel_controller.limit(limits=4):
223
# BLAS: 1 thread, OpenMP: 4 threads
224
result = hybrid_computation()
225
```
226
227
### Dynamic Library Management
228
229
```python
230
from threadpoolctl import ThreadpoolController
231
import importlib
232
233
# Controller state can change as new libraries are loaded
234
initial_controller = ThreadpoolController()
235
print(f"Initial libraries: {len(initial_controller)}")
236
237
# Load library that brings in new thread pools
238
import some_blas_library
239
240
# Need new controller to detect newly loaded libraries
241
updated_controller = ThreadpoolController()
242
print(f"After import: {len(updated_controller)}")
243
244
# Compare library sets
245
initial_libs = {lib.filepath for lib in initial_controller.lib_controllers}
246
updated_libs = {lib.filepath for lib in updated_controller.lib_controllers}
247
new_libs = updated_libs - initial_libs
248
print(f"New libraries: {list(new_libs)}")
249
```
250
251
### Error Handling and Edge Cases
252
253
```python
254
from threadpoolctl import ThreadpoolController
255
256
controller = ThreadpoolController()
257
258
# Handle empty selections
259
blis_controller = controller.select(internal_api='blis')
260
if len(blis_controller) == 0:
261
print("No BLIS libraries found")
262
else:
263
with blis_controller.limit(limits=1):
264
result = computation()
265
266
# Robust library access
267
openblas_controllers = controller.select(internal_api='openblas')
268
if openblas_controllers:
269
for lib in openblas_controllers.lib_controllers:
270
try:
271
# Some old OpenBLAS versions may not support all operations
272
threads = lib.num_threads
273
lib.set_num_threads(1)
274
lib.set_num_threads(threads) # Restore
275
except Exception as e:
276
print(f"Library {lib.prefix} error: {e}")
277
```