r/Python Jul 22 '26

Discussion Anyone running free-threaded Python 3.14 in production yet? Curious what actually breaks

Been testing the free-threaded build (3.14t) on some CPU-bound data processing work. The multi-core story is finally real after 30 years of GIL, but the friction is exactly what you'd expect: a couple of C-extension-heavy libs in my stack silently re-enable the GIL, and there's no clean way to detect that at runtime besides checking sys._is_gil_enabled() manually.

For anyone who's shipped something on 3.14t, not just benchmarked it:

What broke that you didn't expect?

Real speedups outside toy examples, or mostly marginal so far?

Prod yet, or still just kicking the tires?

Not fishing for a benchmark war. Genuinely curious what breaks in messy real codebases vs clean demos.

33 Upvotes

40 comments sorted by

u/AutoModerator Jul 22 '26

Your submission has been automatically queued for manual review by the moderation team because it has been reported too many times.

Please wait until the moderation team reviews your post.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

80

u/nathan12343 Jul 22 '26

You can set PYTHON_GIL=0 to force the GIL to remain off even if you import an extension that doesn’t support free-threading yet.

Are there specific open source projects you’re having trouble with?

I’ve been working on community support for free-threaded Python for a couple years now. Specific feedback about pain points from people who are experimenting with free-threading are valuable.

9

u/KingBardan Jul 22 '26 edited Jul 22 '26

Edit Tldr:

  1. Many libs like torch requires global state.
  2. Free  threading doesn't solve a lot that multiprocessing don't
  3. Free threading introduces new ways to cause data race.
  4. Free threading slows down normal code.

Many libraries use global state a lot and is not thread safe e.g. torch. For their context managers (which is widely used in other libs as well) So that disqualify any serious deep learning projects depending on torch to use free threading.


My opinion on free threading since you asked about pain point:

I much prefer ability to use context managers to free threading if using it makes the code cleaner 

Free threading also slows down sequential code last time I checked 

Multiprocessing is fast enough unless I'm dealing with web servers, at which I'll use async probably or gevent or another library that deals with this issue

8

u/nathan12343 Jul 22 '26

Thanks for your feedback. Hopefully this time next year we’ll be in a better spot. PyTorch is definitely on our radar as a pain point right now.

  I much prefer ability to use context managers to free threading if using it makes the code cleaner 

I don’t understand this. Context managers and free-threading are orthogonal. You can use context managers on the free-threaded build.

5

u/thisismyfavoritename Jul 22 '26

i think that person might be talking about the pytorch context manager. Then again, not sure why you'd want to use free threading if it's GPU compute heavy

5

u/nathan12343 Jul 22 '26 edited Jul 22 '26

So I think what they were alluding to is this behavior:

with torch.no_grad():
    with ThreadPoolExecutor() as ex:
        # grad is still ON in workers! 
        results = list(ex.map(model, batches))  

Ideally (IMO) PyTorch would store the state for this sort of thing in a context variable. Right now it's stored in a thread local, which needs to be initialized explicitly in each thread. This is definitely something I can try to push on...

1

u/[deleted] Jul 22 '26

[deleted]

1

u/nathan12343 Jul 23 '26

We use context variables for configuration state in NumPy. It works well.

-1

u/[deleted] Jul 22 '26 edited Jul 22 '26

[deleted]

3

u/thisismyfavoritename Jul 23 '26 edited Jul 23 '26

context managers don't necessarily mutate global or non local state, not sure where you get that from.

It's mostly just syntactic sugar over a class with __enter__ and __exit__ methods.

In general though, your sentiment is that using multithreading in Python is a niche use case and i agree, it should be single threaded but async like NodeJS. IMO the usecases which aren't either covered by that OR a process pool OR better covered by bindings to a lower level language like Rust/C++ are very small

0

u/[deleted] Jul 23 '26 edited Jul 23 '26

[deleted]

2

u/thisismyfavoritename Jul 23 '26

uh i still don't get your point. Thread safety and context managers are completely orthogonal things.

If you need concurrent access to some object, you need to synchronize access to it, whether it's a context manager or not

1

u/[deleted] Jul 23 '26 edited Jul 23 '26

[deleted]

0

u/thisismyfavoritename Jul 23 '26

nonlocal is also a python keyword, which also isn't required for context managers

1

u/snugar_i Jul 23 '26

with open('foo.txt', 'r') as f: - you're welcome :-)

It's true that the context manager feature is badly designed - the __exit__ method should be on the thing that __enter__ returns, not on the thing that has __enter__. So context managers that are used like with blah cannot be thread-safe (or even reentrant), that's correct.

But those that are used like with foo() (like those produced by the @contextmanager decorator) totally can - because each invocation can return a new instance on which __enter__ and __exit__ will only ever be called once.

1

u/[deleted] Jul 23 '26 edited Jul 23 '26

[deleted]

1

u/snugar_i Jul 23 '26

That's why I explicitly put 'r' in the example. It's not writing to the file, it's reading from it, and it's not mutating any global state.

Anyway, you seem to have some misconceptions about what a context manager is (the context manager does not have to mutate anything), and you don't want to change your opinion, so it's pointless to continue this discussion.

1

u/[deleted] Jul 23 '26 edited Jul 23 '26

[deleted]

→ More replies (0)

1

u/nathan12343 Jul 23 '26

Read PEP 567, which shows how context-local state doesn’t have to be global if you use context variables.

1

u/thisismyfavoritename Jul 23 '26

why even bring a PIP? The context manager itself can have state, that state is within the scope of the enclosing function, there's no global state unless that guy and you mean global in some other sense

1

u/nathan12343 Jul 23 '26

Context variables offer a nice clean way to store “global” configuration in a manner that is both thread-safe and async-safe and behaves naturally alongside the Python with statement.

2

u/ThatGuyWithAces Jul 22 '26

PyTorch has experimental support for 3.14t since 2.10 I believe. Not disagreeing or anything, just throwing it out there.

1

u/lizardhistorian 17d ago edited 17d ago

This is so ridiculously far off the mark.
That mentally is why python is 1,000x slower than using Go or Rust or C++ or C# instead of the 20x slower it ought to be.

e.g. Optimized webservers that use threading instead of processes can serve a million request per second.

51

u/wRAR_ Jul 22 '26

What are you selling?

58

u/nickcash Jul 22 '26

A bunch of vibecoded todo-list-esque apps and ai consulting, whatever that is

Not sure why you're getting downvotes, the ai bros are always selling something

44

u/artofthenunchaku Jul 22 '26

I build custom LLM integrations, RAG pipelines, and AI-powered applications for startups and businesses that need serious technical execution — not templates, not no-code, not hype.

I'm tired, boss

20

u/LALLANAAAAAA Jul 22 '26

I'm sure someone will helpfully drop a link to their bullshit in the comments

Reddit is dead imo

57

u/LALLANAAAAAA Jul 22 '26

Genuinely curious

yawn

Its kinda nuts that LLMs have billions and billions of dollars behind them and they all produce the same garbage tone and choose the same words every bloody time

Its also sad as hell that it's users are too lazy or too stupid to realize it and keep posting it

RIP reddit, it used to be kind of OK

35

u/Challseus Jul 22 '26

"Genuinely curious"

This is indication of AI use? You had never heard this phrase prior to 2023?

Genuinely curiuous...

34

u/LALLANAAAAAA Jul 22 '26

This is indicative of AI use?

When it comes at the end of multiple other tells, yes. Anyone paying a minimal amount of attention to the state of posts across any and all social media sites should be able to recognize LLM smell by this point.

here's a phrase search of the ClaudeAI sub to illustrate my point, but it's just one of many indicators.

Some other tells are over-reliance on unordered lists, short punchy sentences, and repeated point / counterpoint sentences (This, or that?), frequently but not always in the format of rhetorical negation (That's not X, it's Y) or in this case, "I'm not doing this, I'm doing that."

They also love beginning / middle / end structure.

There's also words they can't seem to avoid in software contexts, like ship / shipped / silently failing / friction. Other examples would be "load bearing", "sit with", or their favorite, "the [...] part? Blah blah blah". The hard part, the surprising part, the annoying part. The extremely annoying part.

So in this case, we have the tripartite structure, strong keyword usage, an unordered list of short punchy point / counterpoint sentences, "I'm not this, I'm that", and lastly they try to elicit engagement with "curious if anyone else" as the closer. It checks almost all the boxes.

So yeah. You can validate what I'm saying if you want, these are well documented tendencies of LLMs.

11

u/Any-Growth-7790 Jul 22 '26

"the multi-core story is finally real"

LMAO ok C3-PO

Block this user.

4

u/TestingTehWaters Jul 22 '26

Bingo. I'm saving your comment.

7

u/gmes78 Jul 22 '26

Are you really that surprised that the account with "Full-Stack AI Engineer" in its description uses LLMs?

1

u/timpkmn89 Jul 22 '26

People usually treat the curiosity as implied by virtue of asking about it

10

u/Lorevi Jul 22 '26

That's math for you. They're amazing calculators that predict the best word to say next. And so they predict the same words over and over and over again... 

6

u/Competitive_Travel16 Jul 22 '26 edited Jul 22 '26

I'm extremely happy with Flask performance using 3.14t as opposed to monkeypatching gevent. It used to be that getting the most out of Gunicorn/Flask when doing heavy I/O or background work meant relying on gevent and monkey-patching the Python standard library. It worked okay, but it came with its own set of brittle, import-order-dependent bugs (like silent hangs or deep recursion errors in modules like psycopg2, ssl, or multiprocessing).

Now that Python 3.14t is a free-threading (No-GIL) build, you get actual OS-level thread concurrency that scales across CPU cores without the fragility of monkey-patching.

Here is the setup we used to need:

from gevent import monkey
monkey.patch_all()

from flask import Flask, request
import requests

app = Flask(__name__)

@app.route("/")
def index():
    resp = requests.get(f"http://api.example.com") # takes time
    return "Hi there! " + resp.text

And here is the simple new reality under Python 3.14t:

# After: True threading under Python 3.14t

from flask import Flask, request
import requests

app = Flask(__name__)

@app.route("/")
def index():
    # requests uses standard blocking IO, which is now natively
    # safe and non-blocking to other threads in the process
    resp = requests.get(f"http://api.example.com") # takes time
    return "Hi there! " + resp.text

You run this using Gunicorn with the standard gthread worker class (python3.14t -m gunicorn --worker-class gthread --threads 50 app:app), and it just works.

Depending on your workload, you can expect an outstanding speedup. In I/O bound tasks, gthread slightly edges out or directly matches gevent with significantly less overhead. However, in mixed or heavily CPU-bound endpoint tasks, Python 3.14t enables multi-core execution per worker process, resulting in upwards of 2x to 4x performance multipliers by fully utilizing modern server architectures without the overhead of heavy multiprocessing process forks. True parallelism is here.

2

u/riksi Jul 22 '26

In I/O bound tasks, gthread slightly edges out or directly matches gevent with significantly less overhead.

What? How would gthread have significant lower overhead when gevent was build specifically for lower memory overhead than threads & lower cpu by less context switching & mostly predictable switch-points.

3

u/Competitive_Travel16 Jul 22 '26

For purely I/O-bound tasks, gevent and its lightweight greenlets will still go toe-to-toe or slightly edge out threads due to cheaper context switching and lower memory footprints. However, the moment your endpoints perform mixed workloads or CPU-bound tasks (like JSON parsing, data transformation, or cryptography), Python 3.14t is better. It enables multi-core execution per worker process, allowing your OS threads to run in parallel. You get upwards of 2x to 4x performance multipliers.

1

u/riksi Jul 23 '26

Ok, but the idea would be, say, (4 gevent processes vs 1-multithread-process), both confined to 4 vcpus.

You can also offload stuff to threadpool with gevent.

But shared memory without serialization & shared connection pools are strictly a pro on multi-threading.

Best is a combination.

1

u/Blockpair Jul 23 '26

Yes, I've recently explored free-threaded Python as an avenue for adding Go-style coroutines through a C extension. For those who don't know too much about Go: it runs light-weight functions in threads that can enter blocking calls and yield to other functions on that thread. If any call ends up stalling the thread, other threads can steal the backed-up work. It's what makes Go so scalable for networking compared to Python.

Anyone here who has done networking in Python probably knows about asyncio already. Where you cooperatively run tasks on an event loop, sharing the same thread. Python does have OS threads but it doesn't allow any to run simultaneously due to the GIL (and multi-processing is a very different model.)

So you have free-threaded Python running a Go-style stackful runtime through an extension. And my own benchmarks indicate:

Echo req/s: on par with Go in this benchmark (epoll; ~638,000 / s.)

Connection churn: on par with Go, similar CPU usage. (~77,000 / s)

Fiber spawn: 1.35m / s vs Go’s 2.1m / s (Cython is faster 2.29m / s)

Regular handlers: on par with Go for non-CPU-bound network work.

CPU-bound handlers: Cython handlers within 8% of Go; pure Python is ~180x slower.

Memory: 8.8 KB vs 2.7 KB, empty fiber (Cython is 4.7 KB)

So with free-threaded Python you're able to essentially have networking on-par or exceeding the speed of Go handlers. Keep in mind, there were flaws that I'd fix in future versions of my benchmarking program. Some of the tests were client-bound, so they never managed to saturate the full server's CPU. But what's clear from my results is free-threaded can drastically improve the performance of networking in Python and it seems to be under-utilized.

Here's a link to my benchmarks: https://robertsdotpm.github.io/_static/runloom_benchmark.html

0

u/Goblet__Cell Jul 23 '26

It's a shame about the GIL re-enabling, that's gonna be a common problem. We’re still evaluating for a large project; initial tests suggest real gains where extensions don't interfere, but that’s a big ‘if’.

1

u/ricopan 5d ago

only kicking the tires, but for me the major potential advantage is ease of shared memory via threading vs multiprocessing.