8000 Add materials for Python 3.13 tutorials · realpython/materials@b9a0481 · GitHub
[go: up one dir, main page]

Skip to content 10000

Commit b9a0481

Browse files
committed
Add materials for Python 3.13 tutorials
1 parent fe6ef2f commit b9a0481

File tree

18 files changed

+1455
-0
lines changed

18 files changed

+1455
-0
lines changed

python-313/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Python 3.13 Demos
2+
3+
This repository contains sample code and data files that demos some of the new features in Python 3.13.
4+
5+
## Introduction
6+
7+
You need Python 3.13 installed to run these examples. See the following tutorial instructions:
8+
9+
- [How Can You Install a Pre-Release Version of Python](https://realpython.com/python-pre-release/)
10+
11+
Note that for testing the free-threading and JIT features, you'll need to build Python from source code with additional compiler flags enabled, as [explained in the tutorial](https://realpython.com/python313-free-threading-jit/#get-your-hands-on-the-new-features). Alternatively, you can run benchmarks using Docker containers as [explained below](#free-threading-and-jit).
12+
13+
You can learn more about Python 3.13's new features in the following Real Python tutorials:
14+
15+
<!-- - [Python 3.13: Cool New Features for You to Try](https://realpython.com/python313-new-features/) -->
16+
- [Python 3.13 Preview: Free Threading and a JIT Compiler](https://realpython.com/python313-free-threading-jit/)
17+
- [Python 3.13 Preview: A Modern REPL](https://realpython.com/python313-repl)
18+
19+
You'll find examples from these tutorials in this repository.
20+
21+
## Examples
22+
23+
This section only contains brief instructions on how you can run the examples. See the tutorials for technical details.
24+
25+
### REPL
26+
27+
28+
29+
### Free-Threading and JIT
30+
31+
You need to enable a few build options to try out the free-threading and JIT features in Python 3.13. You can find more information in the dedicated [README file](free-threading-jit/README.md).
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
FROM ubuntu:latest AS free-threaded-builder
2+
3+
# Install dependencies
4+
RUN apt update && \
5+
apt upgrade -y && \
6+
DEBIAN_FRONTEND=noninteractive apt install -y \
7+
wget unzip build-essential pkg-config zlib1g-dev python3 clang
8+
9+
# Download Python 3.13 source code
10+
ARG BASE_URL=https://github.com/python/cpython/archive/refs/tags
11+
ARG ZIP_FILE=v3.13.0rc1.zip
12+
RUN wget -P /tmp $BASE_URL/$ZIP_FILE && \
13+
unzip -d /tmp /tmp/$ZIP_FILE
14+
15+
# Build free-threaded Python 3.13
16+
WORKDIR /tmp/cpython-3.13.0rc1/
17+
RUN ./configure --disable-gil --enable-experimental-jit --enable-optimizations && \
18+
make -j$(nproc) && \
19+
make altinstall
20+
21+
FROM free-threaded-builder AS jit-builder
22+
23+
# Build Python 3.13 with JIT only
24+
WORKDIR /tmp/cpython-3.13.0rc1/
25+
RUN make clean && \
26+
./configure --enable-experimental-jit --enable-optimizations --prefix=/python3.13-jit && \
27+
make -j$(nproc) && \
28+
make install && \
29+
ln -s /python3.13-jit/bin/python3.13 /usr/local/bin/python3.13j
30+
31+
FROM jit-builder AS stock-builder
32+
33+
# Build stock Python 3.13
34+
WORKDIR /tmp/cpython-3.13.0rc1/
35+
RUN make clean && \
36+
./configure --enable-optimizations && \
37+
make -j$(nproc) && \
38+
make install
39+
40+
FROM ubuntu:latest AS final
41+
42+
COPY --from=jit-builder /python3.13-jit /python3.13-jit
43+
COPY --from=stock-builder /usr/local /usr/local
44+
45+
# Install Python provided by the system
46+
RUN apt update && \
47+
apt install -y python3 && \
48+
apt clean && rm -rf /var/lib/apt/lists/*
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
# Python 3.13 Preview: Free Threading and a JIT Compiler
2+
3+
This repository contains sample code and data files for the [Python 3.13 Preview: Free Threading and a JIT Compiler](https://realpython.com/python313-free-threading-jit/) tutorial on Real Python.
4+
5+
## Build the Docker Image
6+
7+
Build Python 3.13 from source code using Docker:
8+
9+
```sh
10+
$ docker image build --tag pythons .
11+
```
12+
13+
**Note:** If you want to compile your C extension modules, then you'll need to keep the intermediate stage with the required build tools:
14+
15+
```sh
16+
$ docker build --target stock-builder --tag builder .
17+
$ docker image build --tag pythons .
18+
```
19+
20+
## Run Performance Benchmarks Using Docker
21+
22+
Change directory to the `benchmarks/` folder:
23+
24+
```sh
25+
$ cd benchmarks/
26+
```
27+
28+
### Free Threading
29+
30+
Run the benchmark against Python 3.12 shipped with the system:
31+
32+
```sh
33+
$ docker run --rm -v "$(pwd)":/app -w /app pythons python3.12 gil.py --threads=4
34+
======================================================
35+
💻 Linux 64bit with 4x CPU cores (x86_64 Little Endian)
36+
🐍 CPython 3.12.3 /usr/bin/python3.12
37+
Free Threading: unsupported
38+
JIT Compiler: unsupported
39+
======================================================
40+
Running 4 threads: 7.33s
41+
```
42+
43+
Run the benchmark against stock Python 3.13:
44+
45+
```sh
46+
$ docker run --rm -v "$(pwd)":/app -w /app pythons python3.13 gil.py --threads=4
47+
======================================================
48+
💻 Linux 64bit with 4x CPU cores (x86_64 Little Endian)
49+
🐍 CPython 3.13.0rc1 /usr/local/bin/python3.13
50+
Free Threading: unsupported
51+
JIT Compiler: unsupported
52+
======================================================
53+
Running 4 threads: 7.51s
54+
```
55+
56+
Run the benchmark against the free-threaded Python 3.13 build with the GIL and JIT disabled:
57+
58+
```sh
59+
$ docker run --rm -v "$(pwd)":/app -w /app -e PYTHON_JIT=0 pythons python3.13t gil.py --threads=4
60+
======================================================
61+
💻 Linux 64bit with 4x CPU cores (x86_64 Little Endian)
62+
🐍 CPython 3.13.0rc1 /usr/local/bin/python3.13t
63+
Free Threading: enabled ✨
64+
JIT Compiler: disabled
65+
======================================================
66+
Running 4 threads: 3.25s
67+
```
68+
69+
Run the benchmark against the free-threaded Python 3.13 build with the GIL enabled and JIT disabled:
70+
71+
```sh
72+
$ docker run --rm -v "$(pwd)":/app -w /app -e PYTHON_JIT=0 pythons python3.13t -X gil=1 gil.py --threads=4
73+
======================================================
74+
💻 Linux 64bit with 4x CPU cores (x86_64 Little Endian)
75+
🐍 CPython 3.13.0rc1 /usr/local/bin/python3.13t
76+
Free Threading: disabled
77+
JIT Compiler: disabled
78+
======================================================
79+
Running 4 threads: 13.72s
80+
```
81+
82+
### Just-In-Time (JIT) Compiler
83+
84+
Run the benchmark against Python 3.12 shipped with the system:
85+
86+
```sh
87+
$ docker run --rm -v "$(pwd)":/app -w /app pythons python3.12 jit.py -n 10000
88+
======================================================
89+
💻 Linux 64bit with 4x CPU cores (x86_64 Little Endian)
90+
🐍 CPython 3.12.3 /usr/bin/python3.12
91+
Free Threading: unsupported
92+
JIT Compiler: unsupported
93+
======================================================
94+
Running fib() 10,000 times: 6.06s
95+
```
96+
97+
Run the benchmark against stock Python 3.13:
98+
99+
```sh
100+
$ docker run --rm -v "$(pwd)":/app -w /app pythons python3.13 jit.py -n 10000
101+
======================================================
102+
💻 Linux 64bit with 4x CPU cores (x86_64 Little Endian)
103+
🐍 CPython 3.13.0rc1 /usr/local/bin/python3.13
104+
Free Threading: unsupported
105+
JIT Compiler: unsupported
106+
======================================================
107+
Running fib() 10,000 times: 5.68s
108+
```
109+
110+
Run the benchmark against Python 3.13 with the JIT enabled but GIL unsupported:
111+
112+
```sh
113+
$ docker run --rm -v "$(pwd)":/app -w /app pythons python3.13j jit.py -n 10000
114+
======================================================
115+
💻 Linux 64bit with 4x CPU cores (x86_64 Little Endian)
116+
🐍 CPython 3.13.0rc1 /usr/local/bin/python3.13j
117+
Free Threading: unsupported
118+
JIT Compiler: enabled ✨
119+
======================================================
120+
Running fib() 10,000 times: 5.27s
121+
```
122+
123+
## Disassemble JIT's Micro-Ops
124+
125+
Reveal mico-ops generated by the JIT compiler:
126+
127+
```sh
128+
$ cd benchmarks/
129+
$ docker run --rm -it -v "$(pwd)":/app -w /app pythons python3.13j -i uops.py
130+
======================================================
131+
💻 Linux 64bit with 4x CPU cores (x86_64 Little Endian)
132+
🐍 CPython 3.13.0rc1 /usr/local/bin/python3.13j
133+
Free Threading: unsupported
134+
JIT Compiler: enabled ✨
135+
======================================================
136+
>>> def fib(n):
137+
... a, b = 0, 1
138+
... for _ in range(n):
139+
... a, b = b, a + b
140+
... return a
141+
...
142+
143+
>>> fib(10)
144+
55
145+
146+
>>> reveal_code(fib)
147+
Micro-ops unavailable
148+
149+
>>> fib(10)
150+
55
151+
152+
>>> reveal_code(fib)
153+
_START_EXECUTOR
154+
_TIER2_RESUME_CHECK
155+
_ITER_CHECK_RANGE
156+
_GUARD_NOT_EXHAUSTED_RANGE
157+
_ITER_NEXT_RANGE
158+
_STORE_FAST_3
159+
_LOAD_FAST_2
160+
_LOAD_FAST_1
161+
_LOAD_FAST_2
162+
_GUARD_BOTH_INT
163+
_BINARY_OP_ADD_INT
164+
_STORE_FAST_2
165+
_STORE_FAST_1
166+
_JUMP_TO_TOP
167+
_DEOPT
168+
_EXIT_TRACE
169+
_EXIT_TRACE
170+
_ERROR_POP_N
171+
_EXIT_TRACE
172+
_ERROR_POP_N
173+
```
174+
175+
## Compile the C Extension Module
176+
177+
Build an intermediate stage with the necessary build tools if you haven't before:
178+
179+
```shell
180+
$ docker build --target stock-builder --tag builder .
181+
```
182+
183+
Change directory to the `c_extension/` folder:
184+
185+
```sh
186+
$ cd c_extension/
187+
```
188+
189+
Start a Docker container from the builder stage and set common compiler flags:
190+
191+
```sh
192+
$ docker run --rm -it -v "$(pwd)":/app -w /app builder
193+
root@8312f61fbb6d:/app# CFLAGS='-shared -fPIC -O3'
194+
```
195+
196+
Compile the `greeter` module for stock Python 3.13:
197+
198+
```sh
199+
root@8312f61fbb6d:/app# gcc greeter.c $CFLAGS \
200+
$(python3.13-config --includes) \
201+
-o greeter_stock.so
202+
```
203+
204+
Compile the `greeter` module for the free-threaded Python 3.13:
205+
206+
```sh
207+
root@8312f61fbb6d:/app# gcc greeter.c $CFLAGS \
208+
$(python3.13t-config --includes) \
209+
-o greeter_threaded_v1.so
210+
```
211+
212+
Compile the `greeter_threaded` module for the free-threaded Python 3.13:
213+
214+
```sh
215+
root@8312f61fbb6d:/app# gcc greeter_threaded.c $CFLAGS \
216+
$(python3.13t-config --includes) \
217+
-o greeter_threaded_v2.so
218+
```
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from argparse import ArgumentParser
2+
from concurrent.futures import ThreadPoolExecutor
3+
from csv import DictWriter
4+
from functools import wraps
5+
from os import cpu_count
6+
from pathlib import Path
7+
from time import perf_counter
8+
from typing import NamedTuple
9+
10+
from pyinfo import print_details, python_short
11+
12+
CSV_PATH = Path(__file__).with_suffix(".csv")
13+
DEFAULT_N = 35
14+
15+
16+
class Record(NamedTuple):
17+
python: str
18+
threads: int
19+
seconds: float
20+
21+
def save(self):
22+
empty = not CSV_PATH.exists()
23+
with CSV_PATH.open(mode="a", encoding="utf-8", newline="") as file:
24+
writer = DictWriter(file, Record._fields)
25+
if empty:
26+
writer.writeheader()
27+
writer.writerow(self._asdict())
28+
29+
30+
def parse_args():
31+
parser = ArgumentParser()
32+
parser.add_argument("-t", "--threads", type=int, default=cpu_count())
33+
parser.add_argument("-n", type=int, default=DEFAULT_N)
34+
return parser.parse_args()
35+
36+
37+
def main(args):
38+
print_details()
39+
benchmark(args.threads, args.n)
40+
41+
42+
def timed(function):
43+
@wraps(function)
44+
def wrapper(num_threads, n):
45+
t1 = perf_counter()
46+
result = function(num_threads, n)
47+
t2 = perf_counter()
48+
duration = t2 - t1
49+
print(f"\b\b\b: {duration:.2f}s")
50+
Record(python_short(), num_threads, duration).save()
51+
return result
52+
53+
return wrapper
54+
55+
56+
@timed
57+
def benchmark(num_threads, n):
58+
with ThreadPoolExecutor(max_workers=num_threads) as executor:
59+
for _ in range(num_threads):
60+
executor.submit(fib, n)
61+
if num_threads > 1:
62+
print(f"Running {num_threads} threads...", end="", flush=True)
63+
else:
64+
print("Running 1 thread...", end="", flush=True)
65+
66+
67+
def fib(n):
68+
return n if n < 2 else fib(n - 2) + fib(n - 1)
69+
70+
71+
if __name__ == "__main__":
72+
main(parse_args())

0 commit comments

Comments
 (0)
0