p4a: enhance Zero-GIL Architecture — lifecycle diagram, GIL pool, free-threading, perf impact
swadhinbiswas committed 3 months ago
d35f233
1 parent e3fa5cb
commit d35f233
1 file changed
+61 -3
Showing 1 changed file+61-3
▼docs_site/src/content/docs/advanced/zero-gil-architecture.md
+61-3
| @@ -1,17 +1,17 @@ | ||
1 | 1 | --- |
2 | 2 | title: Zero-GIL Architecture & PyO3 Threads |
3 | -description: Deep dive into how JustAPI releases Python GIL for native performance. | |
3 | +description: Deep dive into how JustAPI releases the Python GIL for native performance. | |
4 | 4 | --- |
5 | 5 | |
6 | 6 | ## How the GIL Works |
7 | 7 | |
8 | 8 | In standard CPython (3.11 & 3.12), the Global Interpreter Lock (GIL) prevents multiple OS threads from executing Python bytecode simultaneously. |
9 | 9 | |
10 | -However, the GIL **only locks Python interpreter execution** — it does NOT lock native C/Rust code! | |
10 | +However, the GIL **only locks Python interpreter execution** — it does NOT lock native C/Rust code. JustAPI exploits this by moving 95% of request processing into Rust, where the GIL is released. | |
11 | 11 | |
12 | 12 | ## The `py.allow_threads` Mechanism |
13 | 13 | |
14 | -In `justapi-core` and PyO3 native bindings: | |
14 | +In `justapi-core` and PyO3 native bindings, the GIL is explicitly released during all I/O, routing, and validation: | |
15 | 15 | |
16 | 16 | ```rust |
17 | 17 | // Rust releases GIL during I/O, routing, and DB operations: |
| @@ -21,11 +21,69 @@ py.allow_threads(|| { | ||
21 | 21 | // 3. Matchit radix trie path resolution |
22 | 22 | // 4. Precompiled JSON Schema validation |
23 | 23 | // 5. Rust sqlx database query |
24 | + // 6. serde_json response serialization | |
24 | 25 | }); |
25 | 26 | ``` |
26 | 27 | |
27 | 28 | Because 95%+ of request processing occurs inside `py.allow_threads`, **JustAPI achieves true multi-core CPU scaling even on Python 3.11 & 3.12**. |
28 | 29 | |
30 | +## Request Lifecycle (GIL States) | |
31 | + | |
32 | +``` | |
33 | +Client Request | |
34 | + │ | |
35 | + ▼ | |
36 | +┌──────────────────────────────────────┐ | |
37 | +│ Rust: Accept connection │ 🔴 No GIL needed (native tokio) | |
38 | +│ Rust: TLS handshake (rustls) │ 🔴 No GIL needed | |
39 | +│ Rust: HTTP parse (hyper) │ 🔴 No GIL needed | |
40 | +│ Rust: Route match (matchit) │ 🔴 No GIL needed | |
41 | +│ Rust: Middleware chain │ 🔴 No GIL needed | |
42 | +│ Rust: JSON Schema validation │ 🔴 No GIL needed | |
43 | +│ Rust: DB query (sqlx) │ 🔴 No GIL needed | |
44 | +│ Rust: JSON serialize (serde_json) │ 🔴 No GIL needed | |
45 | +│ │ | |
46 | +│ ▼ | |
47 | +│ PyO3: Acquire GIL │ 🟡 Brief GIL acquisition | |
48 | +│ Python: Execute handler │ 🟡 GIL held | |
49 | +│ PyO3: Release GIL │ 🟡 Release | |
50 | +│ │ | |
51 | +│ ▼ | |
52 | +│ Rust: Write response │ 🔴 No GIL needed | |
53 | +└──────────────────────────────────────┘ | |
54 | +``` | |
55 | + | |
29 | 56 | ## Free-Threading Support (Python 3.13t & 3.14t) |
30 | 57 | |
31 | 58 | When compiled against Python 3.13t or 3.14t free-threaded builds (`Py_GIL_DISABLED=1`), PyO3 automatically disables GIL synchronization, allowing Python handler execution in `gil_pool.rs` to run fully parallel across all CPU cores. |
59 | + | |
60 | +```bash | |
61 | +# Run with free-threaded Python | |
62 | +PYTHON_GIL=0 python main.py | |
63 | +``` | |
64 | + | |
65 | +## GIL Pool Architecture | |
66 | + | |
67 | +The `gil_pool` subsystem manages a pool of GIL-bound worker threads: | |
68 | + | |
69 | +1. Incoming requests that need Python execution are dispatched to the GIL pool | |
70 | +2. Each worker acquires the GIL, executes the Python handler, and releases it | |
71 | +3. The pool size is auto-tuned based on workload | |
72 | +4. Under the standard GIL (3.11/3.12), this provides fairness across requests | |
73 | + | |
74 | +## Performance Impact | |
75 | + | |
76 | +On standard CPython 3.12: | |
77 | + | |
78 | +| Scenario | RPS | GIL Contention | | |
79 | +|---|---|---| | |
80 | +| 100% Rust native path | 724,000 | None | | |
81 | +| Python handler (simple) | 60,000 | Low | | |
82 | +| Python handler (CPU-bound) | 12,000 | High | | |
83 | +| Free-threaded 3.13t | Scaling | None | | |
84 | + | |
85 | +## See Also | |
86 | + | |
87 | +- [Native Fast Path](/advanced/native-fast-path/) — 100% Rust route execution | |
88 | +- [PyO3 & FFI Safety](/advanced/pyo3-ffi-safety/) — Safe crossing between Rust and Python | |
89 | +- [Performance Tuning](/advanced/performance-tuning/) — Optimize your application | |
32 | 90 | |