Skip to content

Commit d86857c

Browse files
committed
Add process lesson
1 parent 994fc09 commit d86857c

10 files changed

Lines changed: 90 additions & 0 deletions

File tree

‎README.de.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ Es gibt zwei Möglichkeiten, die Module auszuführen:
119119
- Template strings: [Template strings (PEP 750)](ultimatepython/advanced/template_strings.py) ( 🤯 )
120120
6. **Nebenläufigkeit**
121121
- Thread: [ThreadPoolExecutor](ultimatepython/concurrency/thread.py) ( 🤯 )
122+
- Process: [ProcessPoolExecutor](ultimatepython/concurrency/process.py) ( 🤯 )
122123
- Asyncio: [async | await](ultimatepython/concurrency/async.py) ( 🤯 )
123124
- Subinterpreters: [concurrent.interpreters](ultimatepython/concurrency/subinterpreters.py) ( 🤯 )
124125
7. **Softwaretechnik**

‎README.es.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ Hay dos maneras de ejecutar los módulos:
117117
- Template strings: [Template strings (PEP 750)](ultimatepython/advanced/template_strings.py) ( 🤯 )
118118
6. **Concurrencia**
119119
- Hilos: [ThreadPoolExecutor](ultimatepython/concurrency/thread.py) ( 🤯 )
120+
- Procesos: [ProcessPoolExecutor](ultimatepython/concurrency/process.py) ( 🤯 )
120121
- Asyncio: [async | await](ultimatepython/concurrency/async.py) ( 🤯 )
121122
- Subinterpretes: [concurrent.interpreters](ultimatepython/concurrency/subinterpreters.py) ( 🤯 )
122123
7. **Ingeniería**

‎README.fr.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ Deux méthodes sont possibles :
126126
- Template strings : [Template strings (PEP 750)](ultimatepython/advanced/template_strings.py) ( 🤯 )
127127
6. **Concurrence**
128128
- Thread : [ThreadPoolExecutor](ultimatepython/concurrency/thread.py) ( 🤯 )
129+
- Processus : [ProcessPoolExecutor](ultimatepython/concurrency/process.py) ( 🤯 )
129130
- Asyncio : [async | await](ultimatepython/concurrency/async.py) ( 🤯 )
130131
- Sous-interpréteurs : [concurrent.interpreters](ultimatepython/concurrency/subinterpreters.py) ( 🤯 )
131132
7. **Ingénierie**

‎README.hi.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ print("Ultimate Python स्टडी गाइड")
100100
- Template strings: [Template strings (PEP 750)](ultimatepython/advanced/template_strings.py) ( 🤯 )
101101
6. **समानांतरता**
102102
- थ्रेड: [ThreadPoolExecutor](ultimatepython/concurrency/thread.py) ( 🤯 )
103+
- प्रोसेस: [ProcessPoolExecutor](ultimatepython/concurrency/process.py) ( 🤯 )
103104
- एसिंको: [async | await](ultimatepython/concurrency/async.py) ( 🤯 )
104105
- सबइंटरप्रेटर: [concurrent.interpreters](ultimatepython/concurrency/subinterpreters.py) ( 🤯 )
105106
7. **इंजीनियरिंग**

‎README.ko.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ print("Ultimate Python 학습 가이드")
108108
- 템플릿 문자열: [템플릿 문자열 (PEP 750)](ultimatepython/advanced/template_strings.py) ( 🤯 )
109109
6. **동시성**
110110
- 스레드: [ThreadPoolExecutor](ultimatepython/concurrency/thread.py) ( 🤯 )
111+
- 프로세스: [ProcessPoolExecutor](ultimatepython/concurrency/process.py) ( 🤯 )
111112
- 비동기: [async | await](ultimatepython/concurrency/async.py) ( 🤯 )
112113
- 서브 인터프리터: [concurrent.interpreters](ultimatepython/concurrency/subinterpreters.py) ( 🤯 )
113114
7. **엔지니어링**

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ There are two ways of running the modules:
120120
- Template strings: [Template strings (PEP 750)](ultimatepython/advanced/template_strings.py) ( 🤯 )
121121
6. **Concurrency**
122122
- Thread: [ThreadPoolExecutor](ultimatepython/concurrency/thread.py) ( 🤯 )
123+
- Process: [ProcessPoolExecutor](ultimatepython/concurrency/process.py) ( 🤯 )
123124
- Asyncio: [async | await](ultimatepython/concurrency/async.py) ( 🤯 )
124125
- Subinterpreters: [concurrent.interpreters](ultimatepython/concurrency/subinterpreters.py) ( 🤯 )
125126
7. **Engineering**

‎README.pt_br.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ Existem duas maneiras de rodar os módulos:
106106
- Template strings: [Template strings (PEP 750)](ultimatepython/advanced/template_strings.py) ( 🤯 )
107107
6. **Concorrência**
108108
- Thread: [ThreadPoolExecutor](ultimatepython/concurrency/thread.py) ( 🤯 )
109+
- Processo: [ProcessPoolExecutor](ultimatepython/concurrency/process.py) ( 🤯 )
109110
- Asyncio: [async | await](ultimatepython/concurrency/async.py) ( 🤯 )
110111
- Subinterpretadores: [concurrent.interpreters](ultimatepython/concurrency/subinterpreters.py) ( 🤯 )
111112
7. **Engenharia**

‎README.zh_tw.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ print("Ultimate Python 學習大綱")
103103
- 模板字串:[Template strings (PEP 750)](ultimatepython/advanced/template_strings.py) ( 🤯 )
104104
6. **併發**
105105
- 執行緒:[ThreadPoolExecutor](ultimatepython/concurrency/thread.py) ( 🤯 )
106+
- 行程:[ProcessPoolExecutor](ultimatepython/concurrency/process.py) ( 🤯 )
106107
- 異步:[async | await](ultimatepython/concurrency/async.py) ( 🤯 )
107108
- 子解釋器:[concurrent.interpreters](ultimatepython/concurrency/subinterpreters.py) ( 🤯 )
108109
7. **工程實踐**

‎ui/parse_lessons.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ def parse_file(filepath: str, relative_path: str) -> dict:
174174
],
175175
"concurrency": [
176176
"thread",
177+
"process",
177178
"async",
178179
"subinterpreters",
179180
],
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
"""
2+
Process-based parallelism via multiprocessing and concurrent.futures.
3+
4+
While threads share memory and are constrained by CPython's Global Interpreter
5+
Lock (GIL) for CPU-bound tasks, multiprocessing spawns independent operating
6+
system processes. Each process has its own memory space and Python interpreter,
7+
allowing CPU-intensive work to execute in parallel across multiple CPU cores.
8+
9+
Key patterns demonstrated:
10+
- `ProcessPoolExecutor`: High-level interface for managing worker processes
11+
- `os.getpid()`: Demonstrating execution across distinct process IDs
12+
- `executor.map()`: Batch mapping inputs across worker processes
13+
- `executor.submit()`: Fine-grained task submission with `Future` objects
14+
- Exception propagation across process boundaries
15+
"""
16+
17+
import os
18+
from concurrent.futures import ProcessPoolExecutor
19+
20+
21+
def compute_square(n: int) -> int:
22+
"""CPU-bound task to square a number."""
23+
return n * n
24+
25+
26+
def get_worker_pid(_: int) -> int:
27+
"""Return the operating system process ID of the worker."""
28+
return os.getpid()
29+
30+
31+
def failing_task(n: int) -> int:
32+
"""Task that raises an exception to demonstrate inter-process error propagation."""
33+
if n < 0:
34+
raise ValueError("Input must be non-negative")
35+
return n
36+
37+
38+
def main() -> None:
39+
main_pid = os.getpid()
40+
41+
# 1. Direct execution establishes baseline behavior in the main process
42+
assert compute_square(3) == 9
43+
assert get_worker_pid(0) == main_pid
44+
assert failing_task(1) == 1
45+
direct_fail = False
46+
try:
47+
failing_task(-1)
48+
except ValueError:
49+
direct_fail = True
50+
assert direct_fail is True
51+
52+
# 2. Using ProcessPoolExecutor with a controlled pool size
53+
with ProcessPoolExecutor(max_workers=2) as executor:
54+
# 3. executor.map processes inputs in parallel across worker processes
55+
numbers = [1, 2, 3, 4, 5]
56+
squares = list(executor.map(compute_square, numbers))
57+
assert squares == [1, 4, 9, 16, 25]
58+
59+
# 3. Prove execution occurs in separate process IDs
60+
worker_pids = set(executor.map(get_worker_pid, range(4)))
61+
# Worker processes have their own PIDs, distinct from the main process
62+
assert main_pid not in worker_pids
63+
assert len(worker_pids) > 0
64+
65+
# 4. executor.submit for individual asynchronous tasks
66+
future = executor.submit(compute_square, 12)
67+
assert future.result() == 144
68+
69+
# 5. Exceptions raised in child processes propagate to future.result()
70+
failing_future = executor.submit(failing_task, -5)
71+
task_failed = False
72+
try:
73+
failing_future.result()
74+
except ValueError as e:
75+
task_failed = True
76+
assert str(e) == "Input must be non-negative"
77+
assert task_failed is True
78+
79+
80+
if __name__ == "__main__":
81+
main()

0 commit comments

Comments
 (0)