# Getting Rid of Daemon Threads

**URL:** <https://discuss.python.org/t/getting-rid-of-daemon-threads/68836>\
**Category:** Core Development\
**Created:** [October 22, 2024, 8:27pm UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836 "2024-10-22T20:27:24Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![eric.snow](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/eric.snow/32/31_2.png) [@eric.snow](https://discuss.python.org/u/eric.snow)\
**Post date:** [October 22, 2024, 8:27pm UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/1 "2024-10-22T20:27:24Z")

</div>

Daemon threads are a regular source of pain in core development and have been for years. I’d like to get rid of them. The impact on the Python community is the deciding factor; I suspect low impact but may be wrong. Your feedback will help.

## Proposal

* * *

At the very least I’d like to do the following:

1. [3.12+] (or earlier) clarify docs about daemon threads and add a warning (see [gh-125857](https://github.com/python/cpython/issues/125857))
2. [3.14] (or earlier) add a deprecation note to the docs ([“soft deprecation”](https://peps.python.org/pep-0387/#soft-deprecation))

If the impact on users is not too much then I’d like to move toward getting rid of daemon threads entirely:

1. [3.14] emit a deprecation warning when `Thread(..., daemon=True)` is called or `thread.daemon` is set to True (`thread.setDaemon()` is already deprecated)
2. [3.27] remove support for daemon threads

## Motivation

* * *

- daemon threads are a consistent cause of crashes in CPython
- daemon threads add complexity to key parts of CPython’s runtime
- the docs have not been clear about the use cases for daemon threads, that they should be avoided, and the alternatives

## Impact

* * *

Community usage:

TBD

Existing users of daemon threads can generally update their code to get the same effect from non-daemon threads. See [gh-125857](https://github.com/python/cpython/issues/125857) for examples.

## Context

* * *

> **(expand)**
>
> ### What Are Daemon Threads?
> 
> From [the docs](https://docs.python.org/3/library/threading.html#thread-objects):
> 
> ```plaintext
> A thread can be flagged as a “daemon thread”. The significance of
> this flag is that the the entire Python program exits when only
> daemon threads are left. The initial value is inherited from the
> creating thread. The flag can be set through the daemon property
> or the daemon constructor argument.
> 
> | Note: Daemon threads are abruptly stopped at shutdown. Their
> | resources (such as open files, database transactions, etc.) may
> | not be released properly. If you want your threads to stop
> | gracefully, make them non-daemonic and use a suitable signalling
> | mechanism such as an Event.
> 
> ```
> 
> ### History
> 
> Daemon threads have been a part of the threading module since it was [added in 1998](https://github.com/python/cpython/commit/7f5013a9a9678e86bff00c97f98e7a92c515b94d) ([Python 1.5.1](https://www.python.org/download/releases/1.5/whatsnew/#from-1-5-to-1-5-1-highlights)). (The low-level “thread” module was [added in 1992](https://github.com/python/cpython/commit/1984f1e1c6306d4e8073c28d2395638f80ea509b), without daemon threads.)
> 
> Why were daemon threads part of that initial API? Mostly because Java threads had them–the threading module was essentially copied from Java’s threading API. Unfortunately, in the case of daemon threads, we eventually learned that what made sense for Java did not make sense for Python.
> 
> Note that in Python 3.12, interpreters created using `Py_NewInterpreterFromConfig()` default to disallowing daemon threads. In 3.14, those created by `InterpreterPoolExecutor` never allow daemon threads. Likewise for the API in PEP 734.
> 
> ### The Pros and Cons of Daemon Threads
> 
> In theory, daemon threads help keep low-priority background tasks from blocking application exit. This could be especially useful when your background task calls some long-running third-party non-Python function that doesn’t offer any way to interrupt it or call it for short intervals.  
> Outside of that case, there aren’t real benefits over the alternatives.
> 
> However, in the last 26 years (since Python 1.5), we’ve learned some of the downsides of daemon threads:
> 
> - harder to reason about what happens during finalization
> - adds significant complexity to CPython thread and finalization code
> - a consistent source of bugs, especially crashes, in CPython
> - conceptually, “daemon” threads is easy to confuse with “daemon” processes, which are in some ways opposites
> 
> Ultimately, the cost to CPython maintenance and stability over the years has been not insignificant and continues to be so.
> 
> One issue that has been a contributing factor is that the docs do not provide a clear message about what daemon threads are for, nor that they should be avoided otherwise. Thus, people end up using them when they shouldn’t.
> 
> ### Daemon Threads in Other Languages
> 
> | language | daemon threads |
> | --- | --- |
> | Java | same as Python’s |
> | C++ | always (explicit join) |
> | C | always (explicit join) |
> | Rust | always (explicit join) |
> | Go | goroutines-only |
> | C# | yes |
> | Haskell | no? |
> | Erlang | no? |
> | Clojure | always (explicit join) |
> | Ruby | always (explicit join) |

---

<div class="post-metadata">

**Author:** ![pitrou](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pitrou/32/28_2.png) [@pitrou](https://discuss.python.org/u/pitrou)\
**Post date:** [October 22, 2024, 9:17pm UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/2 "2024-10-22T21:17:08Z")

</div>

> [@eric.snow](#):
>
> At the very least I’d like to do the following:
> 
> 1. [3.12+] (or earlier) clarify docs about daemon threads and add a warning (see [gh-125857](https://github.com/python/cpython/issues/125857))
> 2. [3.14] (or earlier) add a deprecation note to the docs ([“soft deprecation”](https://peps.python.org/pep-0387/#soft-deprecation))
> 
> If the impact on users is not too much then I’d like to move toward getting rid of daemon threads entirely:

It would be nice to get an idea of which packages have a non-trivial use of daemon threads (perhaps using a code search on GitHub?). For example `dask.distributed` has a number of them – some of which I plead guilty for: [Code search results · GitHub](https://github.com/search?q=repo%3Adask%2Fdistributed%20daemon&type=code)

> [@](#):
>
> 1. [3.14] emit a deprecation warning when `Thread(..., daemon=True)` is called or `thread.daemon` is set to True (`thread.setDaemon()` is already deprecated)
> 2. [3.27] remove support for daemon threads

I’m +1 on the idea of emitting a warning, but perhaps we should make it either `RuntimeWarning` or `ResourceWarning`, to ensure that people see it.

As for the removal, I think it should be far enough in the future so that people have time to migrate code away (but 3.27 seems _very_ far away, or did you mean 3.17?).

> [@eric.snow](#):
>
> Existing users of daemon threads can generally update their code to get the same effect from non-daemon threads. See [gh-125857](https://github.com/python/cpython/issues/125857) for examples.

I’m not sure these examples are very helpful. Ok, if you can do with checking a boolean flag from time to time, then you’re set. But otherwise this leaves you the choice between the private `threading._register_atexit` function or the very dubious `PyThreadState_SetAsyncExc` function?

I would certainly try to avoid `PyThreadState_SetAsyncExc` in production code. It may induce misbehavior by interrupting code that does not expect to be interrupted. It may be silenced by an exception-catching clause, or because the exception is raised when running a destructor. Yes, it’s not necessarily worse than daemon threads, but it’s not obviously better either (depends on the exact use case?).

---

<div class="post-metadata">

**Author:** ![pf\_moore](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pf_moore/32/35_2.png) [@pf\_moore](https://discuss.python.org/u/pf_moore)\
**Post date:** [October 22, 2024, 9:37pm UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/3 "2024-10-22T21:37:19Z")

</div>

When I’ve needed daemon threads, it’s usually been the case of “Long-running, uninterruptible, third-party task” in terms of the examples in the linked issue. Basically I’ve had something that I need running in the background, but I have no easy way to terminate it short of process termination. Unfortunately, I’m on Windows, so `signal.pthread_kill` isn’t an option. I guess I could use the Windows `Terminate Thread` API, but it’s a lot of work to wrap it myself compared to just letting process termination handle things.

It’s not something I’ve needed to do often, but it is sometimes an expedient solution to a problem that’s difficult to handle any other way.

I’d be OK with removing daemon threads if we (1) documented `threading._register_atexit`, (2) exposed `PyThreadState_SetAsyncExc` at the Python level, and (3) provided a cross-platform version of `signal.pthread_kill`. That way we could document a reliable alternative for daemon threads, for people who either do need them or aren’t aware that there are better options.

---

<div class="post-metadata">

**Author:** ![cameron](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cameron/32/2658_2.png) [@cameron](https://discuss.python.org/u/cameron)\
**Post date:** [October 22, 2024, 10:33pm UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/4 "2024-10-22T22:33:05Z")

</div>

> Daemon threads are a regular source of pain in core development and  
> have been for years. I’d like to get rid of them. The impact on the  
> Python community is the deciding factor; I suspect low impact but may  
> be wrong. Your feedback will help.

Well, in my personal codebase I have quite a few.

_Most_ of them are little tickers, like a “live” status bar. These can  
all be modified to poll a flag and exit. I’d be entirely happy for that  
flag to be a global such as `threading.shutting_down` or something.

However some of them are workers consuming a queue. As such, they’re  
blocked until a queue item arrives - I’d be quite miffed to do some kind  
of horrible timed-out-queue-next so that I could interleave some flag  
check. Provided my queue shutdown is nice and orderly this won’t be  
necessary. I’m pretty sure I have some things where this isn’t so easy,  
though I’d need to go looking.

But the other side effect is that this is a breaking change. Suddenly a  
million programmes with tickers and other unimportant tasks simply…  
won’t exit. Because their daemon threads will just sit around, where  
formerly they would quietly expire.

I’m assuming that such a change will actually prevent creating “daemon”  
threads in the first place.

As an outsider to the internals, is there a reason that daemon threads  
can’t be shut down by raising some `ThreadingShutdown` exception?

This would allow tidy shutdown of daemon threads with the opportunity  
for clean up of resources they hold open, without foisting gratuitous  
polling on an otherwise blocking workflow.

> ## Motivation
> 
> - daemon threads are a consistent cause of crashes in CPython

I remain quite surprised by this, but if threads are just… cut off  
them I suppose there may be a million tiny edge cases.

> - daemon threads add complexity to key parts of CPython’s runtime

This surprises me also. But again, I’m ignorant about the  
implementation.

> - the docs have not been clear about the use cases for daemon threads, that they should be avoided, and the alternatives

This seems to me to stem from the rather rude “abruptly stopped at  
shutdown” situation. Surely a polite exception would produce better  
semantics. Followed by rudeness for those which decided to catch the  
exception and not quit.

---

<div class="post-metadata">

**Author:** ![njs](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/njs/32/204_2.png) [@njs](https://discuss.python.org/u/njs)\
**Post date:** [October 22, 2024, 11:00pm UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/5 "2024-10-22T23:00:36Z")

</div>

Trio relies heavily on daemon threads. I don’t remember the full details because thread pool design is always very intricate, but at the time I definitely came to the conclusion that daemon threads were the only reasonable option and realistically I’m not going to revisit it without some incredibly compelling reason. IIRC anyio tried very hard to avoid using them based on general “daemon threads are evil” vibes and eventually gave up and switched to using them too, though I wasn’t directly involved there and am not clear on the details.

PyState\_SetAsyncExc and pthread\_kill are much worse than daemon threads, IMO. Daemon threads have well-defined semantics and work reliably today; PyState\_SetAsyncExc and pthread\_kill don’t work and cannot work reliably. I’m not familiar with threading.\_register\_atexit, but I don’t see how it would help, since the fundamental problem is that the only safe way to kill a thread is to kill the enclosing process, and that’s a fact about operating systems that is out of our control.

---

<div class="post-metadata">

**Author:** ![gpshead](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/gpshead/32/54_2.png) [@gpshead](https://discuss.python.org/u/gpshead)\
**Post date:** [October 22, 2024, 11:24pm UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/6 "2024-10-22T23:24:34Z")

</div>

> [@njs](#):
>
> Daemon threads have well-defined semantics and work reliably today

Except that daemon threads don’t actually work reliably. They’re attempting to run and use Python interpreter resources _after_ the runtime has been shut down upon runtime finalization. As in they have pointers to global state for the interpreter. Long ago these were often static globals in the process so they got away with it. But we’ve significantly turned our interpreter state into what it always should’ve been: an allocated controlled per interpreter allocated and managed set of memory.

Now daemon threads running means they attempt to access that after it has been freed. Who likes debugging that?

`pthread_kill` is 100% unusable and should be ignored. It is not possible to _safely_ forcably kill a thread.

---

<div class="post-metadata">

**Author:** ![gpshead](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/gpshead/32/54_2.png) [@gpshead](https://discuss.python.org/u/gpshead)\
**Post date:** [October 22, 2024, 11:30pm UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/7 "2024-10-22T23:30:59Z")

</div>

From experience, you will find that lots of things rely on them (I’m not even including what Nathaniel mentioned) because they are temptingly convenient _sounding_… But the concept is at odds with being able to ever finalize an interpreter.

Realize however that even if we get rid of daemon threads, extension module code can and does spawn its own threads that are not tracked by Python. Those often do want to call into the Python runtime (at which point we dynamically create a Python thread state for them IIRC). Those are realistically an alternate form of daemon thread (I don’t believe we join them upon finalization) and those are never going to be forbidden.

So there isn’t a lot we can do. We’re already doing migitation steps like trying to have threads that attempt to reenter a finalizing runtime just hang forever because our C API surface for GIL acquisition doesn’t have a way to indicate any form of error.

---

<div class="post-metadata">

**Author:** ![njs](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/njs/32/204_2.png) [@njs](https://discuss.python.org/u/njs)\
**Post date:** [October 22, 2024, 11:42pm UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/8 "2024-10-22T23:42:25Z")

</div>

> [@gpshead](#):
>
> But the concept is at odds with being able to ever finalize an interpreter.

Yeah, and IMO when these are irreconcilable the solution is to give up on finalization, not daemon threads. Finalization can’t be made reliable/deterministic in general – this is hardly the only issue with code that’s unprepared to run in an interpreter that’s half-way shut down, and finalization’s already full of weird hacks like clearing module namespaces in some heuristic order and running the GC “hopefully enough times”. I don’t mind making the attempt at supporting finalization as a best-effort you-get-to-keep-both-pieces kind of feature, but we shouldn’t give up fundamentally useful primitives like daemon threads for it.

---

<div class="post-metadata">

**Author:** ![cameron](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cameron/32/2658_2.png) [@cameron](https://discuss.python.org/u/cameron)\
**Post date:** [October 23, 2024, 12:53am UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/9 "2024-10-23T00:53:08Z")

</div>

And this is what surprises me. I’d have _expected_ that the shutdown of  
the runtime which involve _descheduling_ all the threads _first_. IMO,  
ideally by raising some (imaginary) `ThreadingSHutdown` exception in  
each `Thread`. And then a little later: rude termination. And then  
_after that_ shutdown of the runtime.

---

<div class="post-metadata">

**Author:** ![csm10495](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/csm10495/32/9731_2.png) [@csm10495](https://discuss.python.org/u/csm10495)\
**Post date:** [October 23, 2024, 2:29am UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/10 "2024-10-23T02:29:08Z")

</div>

Should this change be a pep?

I’ve seen them used a bunch for fire-and-forget tasks. Daemon threads are common enough that I figure a pep should be written with alternatives for various cases, etc. as part of an official removal plan.

I guess having a way to easily stop threads on shutdown would work out similarly here.

---

<div class="post-metadata">

**Author:** ![gpshead](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/gpshead/32/54_2.png) [@gpshead](https://discuss.python.org/u/gpshead)\
**Post date:** [October 23, 2024, 3:08am UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/11 "2024-10-23T03:08:35Z")

</div>

A PEP? If we were going to do it… perhaps yes to record all of this.

Instead, we _could_ wind up just doubling down on the “if threads the interpreter knows have touched it before still exist in the process at the OS level, disallow complete finalization.”

fwiw “just raise a nice exception” in the threads is a similar problem as to why we can’t do anything other than hang them when they attempt to reenter the CPython runtime: There is no error reporting mechanism at that level to allow them to see they got an exception in a GIL enabled world because there is no error handling and thus exception path available in the GIL acquire code path. We could inject a pending exception into _some_, but guaranteeing all doesn’t seem feasible. And this needs to be fundamentally uncatchable anyways as we can’t let a daemon thread keep the process alive. By definition. So it isn’t really an “exception” kind of thing.

_(i have no idea what the free threading implications are for daemon threads other than I presume “worse” as in “more likely to crash due to things having disappeared and there’s no common reentrancy point that can check for that”)_

---

<div class="post-metadata">

**Author:** ![gpshead](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/gpshead/32/54_2.png) [@gpshead](https://discuss.python.org/u/gpshead)\
**Post date:** [October 23, 2024, 3:16am UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/12 "2024-10-23T03:16:22Z")

</div>

> [@njs](#):
>
> Trio relies heavily on daemon threads. I don’t remember the full details because thread pool design is always very intricate, but at the time I definitely came to the conclusion that daemon threads were the only reasonable option

I’m very curious as to the historical why’s of that kind of conclusion from either `trio` or `anyio`. (I trust they’re real, I just want to page in more understanding)

---

<div class="post-metadata">

**Author:** ![h-vetinari](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/h-vetinari/32/1220_2.png) [@h-vetinari](https://discuss.python.org/u/h-vetinari)\
**Post date:** [October 23, 2024, 4:16am UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/13 "2024-10-23T04:16:07Z")

</div>

> [@pitrou](#):
>
> As for the removal, I think it should be far enough in the future so that people have time to migrate code away (but 3.27 seems _very_ far away, or did you mean 3.17?).

Sidenote: pretty sure this is assuming the acceptance of [PEP 2026](https://peps.python.org/pep-2026/), with would mean that 3.27 gets released in Oct. 2027, two years after the release of 3.14.

---

<div class="post-metadata">

**Author:** ![njs](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/njs/32/204_2.png) [@njs](https://discuss.python.org/u/njs)\
**Post date:** [October 23, 2024, 6:20am UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/14 "2024-10-23T06:20:13Z")

</div>

> [@gpshead](#):
>
> I’m very curious as to the historical why’s of that kind of conclusion from either `trio`

I know one issue is:

For various reasons, you have to do DNS lookups using the OS `getaddrinfo` (it’s the only thing that really knows how DNS is configured locally, cf even Go eventually giving in and adding a `getaddrinfo` fallback)

But, this might block for an arbitrary amount of time, and you want network connections and other things that do DNS lookups to be cancellable and responsive (obviously no-one is writing web browsers in Python, but to get the intuition, you want hitting “stop” on your web page load to actually stop, that’s a thing that should be possible to implement with an IO library)

And once you have called `getaddrinfo` there is no way to stop it, except waiting for it to return or exiting the process.

Therefore: the way `await trio.socket.getaddrinfo(...)` works is to internally kick off a call to real-OS-`getaddrinfo` on a daemon thread, then puts the calling task to sleep until either the `getaddrinfo` completes _or_ the Python-level operation gets cancelled. If it gets cancelled, then we cut the thread loose to continue running in the background (which is safe b/c `getaddrinfo` is side-effect-free and will complete _eventually_), and the `await trio.socket.getaddrinfo(...)` returns immediately.

Example of why this matters: run a Python script. Realize you passed in the wrong arguments, hit control-C, expected behavior: script exits immediately. Currently with Trio this generally works even if the script did a DNS lookup, because we unwind the user’s Python code and exit, and then the lingering daemon thread in `getaddrinfo` gets forcibly terminated by the OS. If it was a regular thread, then the unwinding would get “stuck” and you’d be sitting there hammering control-C waiting for `getaddrinfo` to return. This will happen eventually – it has internal timeouts – but it might take, say, 5-10 seconds.

I think it’s actually impossible to get the desired behavior here _without_ either using daemon threads, or else calling `os._exit` at the end of your script? And Trio can’t call `os._exit` because it’s a library.

(I assume this is part of why every OS and Java all provide something semantically equivalent to daemon threads as an option.)

* * *

I do get that the underlying issue here is that Eric has a larger project of making Python interpreters into things that can be reliably created and destroyed within a process. And conceptually I absolutely get how that’s the elegant thing, and it’s ugly and frustrating that Python wasn’t built that way from the beginning. I’m not happy to be pointing out that we’ve painted ourselves into a corner. But the reality is that for however many decades now in practice we’ve always had 1 Python interpreter = 1 process, and they terminate together. And daemon threads are a widely-used part of our public API that rely on that fact. So I think we have to cope somehow.

---

<div class="post-metadata">

**Author:** ![pitrou](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pitrou/32/28_2.png) [@pitrou](https://discuss.python.org/u/pitrou)\
**Post date:** [October 23, 2024, 7:35am UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/15 "2024-10-23T07:35:54Z")

</div>

> [@njs](#):
>
> Example of why this matters: run a Python script. Realize you passed in the wrong arguments, hit control-C, expected behavior: script exits immediately. Currently with Trio this generally works even if the script did a DNS lookup, because we unwind the user’s Python code and exit, and then the lingering daemon thread in `getaddrinfo` gets forcibly terminated by the OS. If it was a regular thread, then the unwinding would get “stuck” and you’d be sitting there hammering control-C waiting for `getaddrinfo` to return. This will happen eventually – it has internal timeouts – but it might take, say, 5-10 seconds.
> 
> I think it’s actually impossible to get the desired behavior here _without_ either using daemon threads, or else calling `os._exit` at the end of your script?

It’s probably possible by spawning your own `getaddrinfo` thread using C or C++ (or Rust!) code.

> [@njs](#):
>
> (I assume this is part of why every OS and Java all provide something semantically equivalent to daemon threads as an option.)

“Every OS and Java” made decisions about their threading APIs long before any of those issues were widely understood, IMHO.

---

<div class="post-metadata">

**Author:** ![ncoghlan](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/ncoghlan/32/14266_2.png) [@ncoghlan](https://discuss.python.org/u/ncoghlan)\
**Post date:** [October 23, 2024, 11:39am UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/16 "2024-10-23T11:39:50Z")

</div>

> [@njs](#):
>
> But the reality is that for however many decades now in practice we’ve always had 1 Python interpreter = 1 process, and they terminate together. And daemon threads are a widely-used part of our public API that rely on that fact. So I think we have to cope somehow.

Possible improvements that seem feasible to me:

- make allowing daemon threads in _sub_interpreters an off-by-default feature. Apps can then decide to turn them on (if they’re needed and the subinterpreter will live for the lifetime of the process), or leave them off and require that any operations that require them be handled in the main interpreter (or a dedicated subinterpreter with daemon threads enabled) rather than each subinterpreter handling the affected tasks directly.
- outright refusing to finalize subinterpreters with running daemon threads outside the context of full Python runtime finalization
- adding `ResourceWarning` when there are any living daemon threads when runtime finalization starts (similar to the existing warning for unawaited coroutines).

Actually dropping daemon threads entirely doesn’t seem feasible (for the various reasons given above).

---

<div class="post-metadata">

**Author:** ![barry-scott](https://avatars.discourse-cdn.com/v4/letter/b/e9c0ed/32.png) [@barry-scott](https://discuss.python.org/u/barry-scott)\
**Post date:** [October 23, 2024, 11:42am UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/17 "2024-10-23T11:42:13Z")

</div>

> [@cameron](#):
>
> I’d have _expected_ that the shutdown of  
> the runtime which involve _descheduling_ all the threads _first_. IMO,  
> ideally by raising some (imaginary) `ThreadingSHutdown` exception in  
> each `Thread`.

That cannot be done reliably. Think of a thread that the python code called into a library written in C that blocks execution for a long time.

---

<div class="post-metadata">

**Author:** ![Liz](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/liz/32/15021_2.png) [@Liz](https://discuss.python.org/u/Liz)\
**Post date:** [October 23, 2024, 1:12pm UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/18 "2024-10-23T13:12:37Z")

</div>

Is there a reason to prefer `getaddrinfo` over `getaddrinfo_a` (`GetAddrInfoExA` on windows) or a reason why these apis arent enough for async name resolution?

I’m assuming that I must be missing a reason this isn’t sufficient given the amount of time you’ve put into trio, but I wonder if whatever reasons those are might be resolvable on the timeline for daemon thread removal.

---

<div class="post-metadata">

**Author:** ![colesbury](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/colesbury/32/28031_2.png) [@colesbury](https://discuss.python.org/u/colesbury)\
**Post date:** [October 23, 2024, 2:26pm UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/19 "2024-10-23T14:26:36Z")

</div>

I don’t think getting rid of daemon threads actually solves any problems and it will be a massive pain for our users.

Our interpreter shutdown process is complex and buggy, but the problems are not specific to daemon threads. We have the same issues with:

- non-daemon threads when you press Ctrl-C (or otherwise have an exception during shutdown)
- Threads created from C via `PyGILState_Ensure()` or similar

Subinterpreters disallow daemon threads, but I don’t think that improves the shutdown situation. The `test_interpreters` test suite often “core dumps” if you press Ctrl-C.

I think the comparison to other languages is backwards: threads in C++, C (pthreads), and Go (goroutines) behave like Python and Java’s daemon threads: non-main threads do not prevent process shutdown. They don’t have **“non-daemon”** threads, where the main thread implicitly calls `join()` on other threads after the main function/module returns.

---

<div class="post-metadata">

**Author:** ![Kwpolska](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/kwpolska/32/10542_2.png) [@Kwpolska](https://discuss.python.org/u/Kwpolska)\
**Post date:** [October 23, 2024, 3:54pm UTC](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836/20 "2024-10-23T15:54:06Z")

</div>

> [@pitrou](#):
>
> It’s probably possible by spawning your own `getaddrinfo` thread using C or C++ (or Rust!) code.

`trio` is pure-Python. Adding C/C++/Rust code to spawn a thread would significantly increase the maintenance burden and decrease usability for users on niche platforms or on platforms the maintainers can’t easily build wheels on, as well as require writing threading code in those languages (which can be painful).

* * *

I can’t really see why daemon threads need to be removed, if they largely work and solve problems well enough in production. Finalization tends to be hard (cf. Java deprecating object finalizers 7 years ago), and sometimes patching the finalization error handler to print “Thank you for playing Wing Commander!” is better than trying to solve all the minor edge cases out there.

If this were accepted, there should be viable alternatives accessible to pure-Python code that solve typical problems currently solved with daemon threads. Also, a two-year deprecation timeline seems way too fast.

[Next page](https://discuss.python.org/t/getting-rid-of-daemon-threads/68836.md?page=2)
