-
Notifications
You must be signed in to change notification settings - Fork 758
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add initial free-threading page for the guide #4577
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good already, added some thoughts that came to mind while reading (from someone who hasn't looked a lot into free-threading yet)
(Nit: Maybe we can use a consistent capitalization of "Python" 🙃)
guide/src/free-threading.md
Outdated
Instead, you can think about whether or not you a rust scope has access to a | ||
Python **thread state** in `ATTACHED` status. See [PEP | ||
703](https://peps.python.org/pep-0703/#thread-states) for more background about | ||
Python thread states and status. In order to use the CPython C API in both the | ||
GIL-enabled and free-threaded builds of CPython, you must own an attached | ||
Python thread state. The `with_gil` function sets this up and releases the | ||
thread state after the closure passed to `with_gil` finishes. Similarly, in both | ||
the GIL-enabled and free-threaded build, you must use `allow_threads` in | ||
order to use rust threads. Both of `with_gil` and `allow_threads` tell CPython | ||
to put the Python thread state into `DETACHED` status. In the GIL-enabled build, | ||
this is equivalent to releasing the GIL. In the free-threaded build, this unblocks | ||
CPython from triggering a stop-the-world for a garbage collection pass. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very valuable information, but also pretty technical. Maybe we should put this in a <details>
tab and summarize that on a higher level, so that it's a bit easier to grasp for new users. Maybe that "GIL" refers to the interaction with the Python interpreter or something like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I agree, the main point that PyO3 still requires attachment to a Python thread to do Python work is a bit blurred with the technical details of how attachment works here.
guide/src/free-threading.md
Outdated
thread state after the closure passed to `with_gil` finishes. Similarly, in both | ||
the GIL-enabled and free-threaded build, you must use `allow_threads` in | ||
order to use rust threads. Both of `with_gil` and `allow_threads` tell CPython |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not quite sure how to interpret the "Rust threads" part. I don't think there is a problem in just spawning Rust thread an doing something different non Python related in the background. It's more about detaching the current thread from it's interaction with the Interpreter and handing back control, if I got that correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, this is already looking great to me! I have a few suggestions too...
guide/src/free-threading.md
Outdated
Instead, you can think about whether or not you a rust scope has access to a | ||
Python **thread state** in `ATTACHED` status. See [PEP | ||
703](https://peps.python.org/pep-0703/#thread-states) for more background about | ||
Python thread states and status. In order to use the CPython C API in both the | ||
GIL-enabled and free-threaded builds of CPython, you must own an attached | ||
Python thread state. The `with_gil` function sets this up and releases the | ||
thread state after the closure passed to `with_gil` finishes. Similarly, in both | ||
the GIL-enabled and free-threaded build, you must use `allow_threads` in | ||
order to use rust threads. Both of `with_gil` and `allow_threads` tell CPython | ||
to put the Python thread state into `DETACHED` status. In the GIL-enabled build, | ||
this is equivalent to releasing the GIL. In the free-threaded build, this unblocks | ||
CPython from triggering a stop-the-world for a garbage collection pass. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I agree, the main point that PyO3 still requires attachment to a Python thread to do Python work is a bit blurred with the technical details of how attachment works here.
guide/src/free-threading.md
Outdated
If you wrote code that makes strong assumptions about the GIL protecting shared | ||
mutable state, it may not currently be straightforward to support free-threaded | ||
Python without the risk of runtime mutable borrow panics. PyO3 does not lock | ||
access to python state, so if more than one thread tries to access a python | ||
object that has already been mutably borrowed, only runtime checking enforces | ||
safety around mutably aliased data owned by the Python interpreter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here there is a point to be made that the user would have knowingly made such an assumption by using unsafe impl
for Send
and/or Sync
(especially if the PyO3 API is correct in its requirements of these).
Thanks for all the comments! I hope the new text addresses the concerns and is clearer. I'd like to add sections on the critical section and PyMutex wrappers, assuming those get merged, and also maybe another section in the docs about multithreaded programming using PyO3? I definitely found it nontrivial to learn and things like |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice, this reads a lot easier to me.
I guess my main concern is still what terminology we use, when we want to talk about interacting with the interpreter.
I think there are now 3 different wordings in different paragraphs. Sometimes it's still referred to as "GIL", then we have "thread state" and we have "attached to the runtime". I think unifying them makes sense to not overload readers. Personally I like the "attached to the runtime" variant because it's high level enough that someone without much experience can get an idea about whats going on (I think?) and it's independent of the build-mode. We can also add a later (sub)section explaining what "attached to the runtime" means as technical documentation.
85c8bf0
to
dc7dde6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking great, thanks! Just a few smaller thoughts, and then let's merge 👍
the GIL is acquired. In the free-threaded build there is no GIL, but the same C | ||
macros that release or acquire the GIL in the GIL-enabled build instead ask the | ||
interpreter to attach the thread to the Python runtime, and there can be many | ||
threads simultaneously attached. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should add a sentence here along the lines of
"Similarly, in the GIL-enabled build PyO3 uses the Python<'py>
type and the 'py
lifetime to signify attachment the global interpreter lock; in the freethreaded build these simply mean the thread is currently attached to the Python interpreter."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I incorporated this and edited the surrounding paragraphs a bit. I think it reads better now, thanks for the suggestion.
f9b347e
to
66f09b8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, thanks!
Moves the existing content on free-threading in the migration guide into its own page. Also adds some new content about things we know are going to be issues for some users.
Comments and suggestions are very welcome. I'd really appreciate ideas for illustrative code examples to add, if anyone has any.