0
# Backend Context
1
2
Loky's backend context management provides functions for configuring multiprocessing contexts, determining system resources, and managing process creation methods. These functions offer enhanced CPU detection and cross-platform compatibility.
3
4
## Capabilities
5
6
### CPU Count Detection
7
8
Enhanced CPU count function with support for physical cores and container awareness.
9
10
```python { .api }
11
def cpu_count(only_physical_cores=False):
12
"""
13
Return the number of CPUs available to the current process.
14
15
This implementation is CFS-aware (Linux Control Groups) and can distinguish
16
between logical and physical cores.
17
18
Parameters:
19
- only_physical_cores (bool): If True, return only physical cores.
20
If False, return logical cores. Default False.
21
22
Returns:
23
int: Number of available CPU cores
24
25
Note:
26
This function respects container limits, CPU affinity settings, and
27
cgroup constraints on Linux systems.
28
"""
29
```
30
31
### Context Management
32
33
Functions for managing multiprocessing contexts and start methods.
34
35
```python { .api }
36
def get_context(method=None):
37
"""
38
Get a multiprocessing context for the specified start method.
39
40
Parameters:
41
- method (str, optional): Start method name ('loky', 'spawn', 'fork', 'forkserver').
42
Defaults to 'loky' if not specified.
43
44
Returns:
45
LokyContext: Multiprocessing context for the specified method
46
47
Available methods:
48
- 'loky': Loky's enhanced context (default)
49
- 'loky_init_main': Special context for main process initialization
50
- 'spawn': Pure spawn context
51
- 'fork': Fork context (POSIX only, not recommended)
52
- 'forkserver': Fork server context (POSIX only)
53
"""
54
55
def set_start_method(method, force=False):
56
"""
57
Set the method for starting worker processes.
58
59
Parameters:
60
- method (str): Start method to use
61
- force (bool): Whether to force setting even if already set. Default False.
62
63
Returns:
64
None
65
66
Raises:
67
RuntimeError: If start method is already set and force=False
68
"""
69
70
def get_start_method():
71
"""
72
Get the current start method.
73
74
Returns:
75
str: Current start method name
76
"""
77
```
78
79
### Context Classes
80
81
Specialized context classes for different process creation strategies.
82
83
```python { .api }
84
class LokyContext:
85
"""Enhanced multiprocessing context with loky-specific features."""
86
def Process(self, *args, **kwargs): ...
87
def Queue(self, maxsize=0): ...
88
def SimpleQueue(self): ...
89
def Lock(self): ...
90
def RLock(self): ...
91
def Semaphore(self, value=1): ...
92
def BoundedSemaphore(self, value=1): ...
93
def Condition(self, lock=None): ...
94
def Event(self): ...
95
96
class LokyInitMainContext(LokyContext):
97
"""Context for main process initialization scenarios."""
98
```
99
100
## Usage Examples
101
102
### Basic CPU Count Usage
103
104
```python
105
from loky import cpu_count
106
107
# Get logical CPU count (includes hyperthreading)
108
logical_cpus = cpu_count()
109
print(f"Logical CPUs: {logical_cpus}")
110
111
# Get physical CPU count (excludes hyperthreading)
112
physical_cpus = cpu_count(only_physical_cores=True)
113
print(f"Physical CPUs: {physical_cpus}")
114
115
# Use for executor sizing
116
from loky import get_reusable_executor
117
executor = get_reusable_executor(max_workers=physical_cpus)
118
```
119
120
### Container-Aware CPU Detection
121
122
```python
123
from loky import cpu_count
124
125
# In containerized environments, cpu_count respects limits
126
available_cpus = cpu_count()
127
print(f"CPUs available to container: {available_cpus}")
128
129
# This is particularly useful in Docker containers with CPU limits
130
# where os.cpu_count() might return the host's CPU count
131
import os
132
host_cpus = os.cpu_count()
133
container_cpus = cpu_count()
134
135
print(f"Host CPUs: {host_cpus}")
136
print(f"Container CPUs: {container_cpus}")
137
```
138
139
### Context Configuration
140
141
```python
142
from loky.backend import get_context
143
from loky.backend.context import set_start_method, get_start_method
144
145
# Set the start method globally
146
set_start_method('loky')
147
148
# Get current start method
149
current_method = get_start_method()
150
print(f"Current start method: {current_method}")
151
152
# Get context for specific method
153
loky_context = get_context('loky')
154
spawn_context = get_context('spawn')
155
156
print(f"Loky context: {loky_context}")
157
print(f"Spawn context: {spawn_context}")
158
159
# Use context to create process-related objects
160
queue = loky_context.Queue()
161
lock = loky_context.Lock()
162
event = loky_context.Event()
163
```
164
165
### Custom Context Usage
166
167
```python
168
from loky import ProcessPoolExecutor
169
from loky.backend.context import get_context
170
171
def worker_function(x):
172
import os
173
return f"Process {os.getpid()}: {x * 2}"
174
175
# Use specific context
176
loky_context = get_context('loky')
177
178
# Create executor with custom context
179
executor = ProcessPoolExecutor(
180
max_workers=2,
181
context=loky_context
182
)
183
184
results = list(executor.map(worker_function, range(5)))
185
for result in results:
186
print(result)
187
188
executor.shutdown()
189
```
190
191
### Cross-Platform Start Method Selection
192
193
```python
194
import sys
195
from loky.backend.context import set_start_method, get_start_method
196
197
def configure_optimal_start_method():
198
"""Configure the best start method for the current platform."""
199
if sys.platform == 'win32':
200
# Windows only supports spawn
201
method = 'spawn'
202
else:
203
# Unix-like systems can use loky (recommended)
204
method = 'loky'
205
206
set_start_method(method, force=True)
207
return method
208
209
# Configure and display start method
210
method = configure_optimal_start_method()
211
current_method = get_start_method()
212
print(f"Configured start method: {method}")
213
print(f"Current start method: {current_method}")
214
```
215
216
### Advanced Context Features
217
218
```python
219
from loky.backend.context import get_context
220
221
# Get loky context with enhanced features
222
ctx = get_context('loky')
223
224
# Create synchronization primitives
225
lock = ctx.Lock()
226
rlock = ctx.RLock()
227
semaphore = ctx.Semaphore(2)
228
condition = ctx.Condition()
229
event = ctx.Event()
230
231
# Create queues
232
queue = ctx.Queue(maxsize=10)
233
simple_queue = ctx.SimpleQueue()
234
235
print("Created loky context objects:")
236
print(f"Lock: {lock}")
237
print(f"RLock: {rlock}")
238
print(f"Semaphore: {semaphore}")
239
print(f"Queue: {queue}")
240
print(f"SimpleQueue: {simple_queue}")
241
```
242
243
### Resource-Aware Executor Configuration
244
245
```python
246
from loky import get_reusable_executor, cpu_count
247
import psutil
248
249
def get_optimal_worker_count():
250
"""Determine optimal worker count based on system resources."""
251
# Get CPU information
252
physical_cores = cpu_count(only_physical_cores=True)
253
logical_cores = cpu_count(only_physical_cores=False)
254
255
# Get memory information (requires psutil)
256
try:
257
memory_gb = psutil.virtual_memory().total / (1024**3)
258
259
# Rule of thumb: 1 worker per 2GB RAM, but not more than physical cores
260
memory_workers = int(memory_gb / 2)
261
optimal_workers = min(physical_cores, memory_workers)
262
263
print(f"Physical cores: {physical_cores}")
264
print(f"Logical cores: {logical_cores}")
265
print(f"Memory: {memory_gb:.1f} GB")
266
print(f"Memory-based workers: {memory_workers}")
267
print(f"Optimal workers: {optimal_workers}")
268
269
return optimal_workers
270
except ImportError:
271
# Fallback if psutil not available
272
return physical_cores
273
274
# Configure executor with optimal worker count
275
optimal_workers = get_optimal_worker_count()
276
executor = get_reusable_executor(max_workers=optimal_workers)
277
```
278
279
### Context Method Comparison
280
281
```python
282
from loky.backend.context import get_context
283
import time
284
285
def timing_test(context_method, iterations=1000):
286
"""Test process creation speed for different context methods."""
287
ctx = get_context(context_method)
288
289
start_time = time.time()
290
291
processes = []
292
for _ in range(iterations):
293
# Create but don't start processes for timing
294
p = ctx.Process(target=lambda: None)
295
processes.append(p)
296
297
creation_time = time.time() - start_time
298
299
# Clean up
300
for p in processes:
301
del p
302
303
return creation_time
304
305
# Compare different context methods (on supported platforms)
306
methods = ['loky', 'spawn']
307
if sys.platform != 'win32':
308
methods.extend(['fork', 'forkserver'])
309
310
print("Process creation timing comparison:")
311
for method in methods:
312
try:
313
elapsed = timing_test(method, 100)
314
print(f"{method}: {elapsed:.4f} seconds")
315
except Exception as e:
316
print(f"{method}: Not available ({e})")
317
```
318
319
## Platform Considerations
320
321
### Windows
322
- Only 'spawn' and 'loky' methods available
323
- Maximum of ~60 workers on older Python versions
324
325
### Unix/Linux
326
- All start methods available ('loky', 'spawn', 'fork', 'forkserver')
327
- 'loky' recommended for robustness
328
- 'fork' not recommended due to thread safety issues
329
330
### Container Environments
331
- CPU count automatically respects container limits
332
- Works with Docker CPU constraints and Kubernetes resource limits
333
- Supports cgroup v1 and v2 CPU accounting