Python 3.13

Hey, I see Python 3.13 was released yesterday. Let's try it!

❯ cd ~/.pyenv

❯ git pull

❯ pyenv install -l | rg 3.13
  3.13.0
  3.13.0t
  3.13-dev
  3.13t-dev
  ...

❯ pyenv install 3.13
Downloading Python-3.13.0.tar.xz...
-> https://www.python.org/ftp/python/3.13.0/Python-3.13.0.tar.xz
Installing Python-3.13.0...
Installed Python-3.13.0 to /home/tim/.pyenv/versions/3.13.0

❯ pyenv global 3.13

❯ python
Python 3.13.0 (main, Oct  8 2024, 07:32:59) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 2 + 3
5

One of the things Python 3.13 has is a new REPL. Among other things, it has fancy colors. They didn't survive the cut and paste above, but here's what it looks like in my terminal

./repl.png

I think I need to install ruff for it too. That is, each version of Python I install needs its own ruff.

❯ pip install ruff
...

Besides the new REPL, there are two more big features in Python 3.13: "free-threading" (disabling the GIL) and JIT Compilation. Both of these are experimental.

It looks like the pyenv folks have compiled a free-threaded version for us, so we can try that out easy-peasy!

❯ pyenv install -l | rg 3.13
  3.13.0
  3.13.0t
  3.13-dev
  3.13t-dev
  ...

That first one, 3.13.0, is what we installed above, the default GIL-enabled Python. But 3.13.0t is the free-threaded version.

❯ pyenv install 3.13.0t
Downloading Python-3.13.0.tar.xz...
-> https://www.python.org/ftp/python/3.13.0/Python-3.13.0.tar.xz
Installing Python-3.13.0...
Installed Python-3.13.0 to /home/tim/.pyenv/versions/3.13.0t
  
❯ pyenv global 3.13.0t

We can see it used the same source code as above, but it was built with the --disable-gil option.

Does it work? Here's a silly program that uses threads.

#!/usr/bin/env python

import os
import threading

def fib(n):
    return n if n < 2 else fib(n - 2) + fib(n - 1)

for _ in range(os.cpu_count()):
    threading.Thread(target=fib, args=(35,)).start()

If we run it with the default version, it takes about a minute.

❯ pyenv global 3.13.0

❯ time ./fibonacci.py 

real	1m5.690s
user	1m6.703s
sys	0m1.760s

But if we run it with the free-threading version, it takes just a few seconds.

❯ pyenv global 3.13.0t

❯ time ./fibonacci.py 

real	0m5.694s
user	1m28.021s
sys	0m0.109s

This machine has 16 threads available.

>>> 65.690 / 5.694
11.536705303828592

It's about 12 times faster, rather than 16, but that's not bad.

With the default version, we were using all the threads, but they were taking turns. Here's the relevant bit of htop.

./htop.not.png

With the free-threading version, each thread stays busy.

./htop.t.png

When I'm interested in going fast, I'm probably not going to choose Python. But this does seem to work!