-
Notifications
You must be signed in to change notification settings - Fork 198
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
Support for free-threaded Python #695
Commits on Sep 20, 2024
-
free-threading: CMake build sytem
This commit adds the ``FREE_THREADED`` parameter to the CMake ``nanobind_add_module()`` command. It does not do anything for now besides defining ``NB_FREE_THREADED`` in C++ compilation units.
Configuration menu - View commit details
-
Copy full SHA for 3cea767 - Browse repository at this point
Copy the full SHA 3cea767View commit details -
Configuration menu - View commit details
-
Copy full SHA for e47d2c9 - Browse repository at this point
Copy the full SHA e47d2c9View commit details -
free-threading: ABI separation
Nanobind's internal data structures switch to a different layout when free-threading was requested. We must give such extensions a different ABI tag since they are incompatible with non-free-threaded ones.
Configuration menu - View commit details
-
Copy full SHA for 84ce61e - Browse repository at this point
Copy the full SHA 84ce61eView commit details -
free-threading: Abstractions around locking API
This commit implements RAII scope guards that are thin wrappers around existing Python API to lock Python mutexes and enter critical sections with respect to one or two Python objects. In ordinary (non-free-threaded) Python builds, they don't do anything and can be optimized away.
Configuration menu - View commit details
-
Copy full SHA for 7d9acee - Browse repository at this point
Copy the full SHA 7d9aceeView commit details -
free-threading: GC adaptations
The garbage collector in free-threaded Python does not like it when the reference count of an object temporarily increases while traversing the object graph in ``tp_traverse``, and doing so introduces leaks. Unfortunately, example implementations of ``tp_traverse`` in both documentation and test suite fall into this trap and must be adapted.
Configuration menu - View commit details
-
Copy full SHA for 510e3e6 - Browse repository at this point
Copy the full SHA 510e3e6View commit details -
free-threading: Locking for internal data structures
This commit enables free-threaded extension builds on Python 3.13+, which involves the following changes: - nanobind must notify Python that an extension supports free-threading. - All internal data structures must be protected from concurrent modification. The approach taken varies with respect to the specific data structure, and a long comment in ``nb_internals.h`` explains the design decisions all of the changes. In general, the implementation avoids centralized locks as much as possible to improve scalability. - Adopting safe versions of certain operations where needed, e.g. ``PyList_GetItemRef()``. - Switching non-object allocation from ``PyObject_Allo()`` to ``PyMem_Alloc()``.
Configuration menu - View commit details
-
Copy full SHA for e02db2d - Browse repository at this point
Copy the full SHA e02db2dView commit details -
free-threading: Immortalize type and function objects
Global objects that undergo a high rate of reference count changes can become a bottleneck in free-threaded Python extensions, since the associated atomic operation require coordination between processor cores. Function and type objects are a particular concern. This commit immortalizes such objects, which exempts them from free-threading. The downside of this is that they will leak.
Configuration menu - View commit details
-
Copy full SHA for 9cf1e8e - Browse repository at this point
Copy the full SHA 9cf1e8eView commit details -
free-threading: Argument-level locking
Adapting C++ to handle parallelism due to free-threaded Python can be tricky, especially when the original code is given as-is. This commit an tentative API to retrofit locking onto existing code by locking the arguments of function calls.
Configuration menu - View commit details
-
Copy full SHA for e70cf49 - Browse repository at this point
Copy the full SHA e70cf49View commit details -
This commit documents free-threading in general and in the context of nanobind extensions.
Configuration menu - View commit details
-
Copy full SHA for 50771a7 - Browse repository at this point
Copy the full SHA 50771a7View commit details -
Several parallel tests to check that locking works as expected
Configuration menu - View commit details
-
Copy full SHA for dd43fe2 - Browse repository at this point
Copy the full SHA dd43fe2View commit details -
Configuration menu - View commit details
-
Copy full SHA for 302ab7c - Browse repository at this point
Copy the full SHA 302ab7cView commit details -
Configuration menu - View commit details
-
Copy full SHA for 13682cb - Browse repository at this point
Copy the full SHA 13682cbView commit details -
Make
nb::dict
iterator non-copyableThis commit changes the ``nb::dict`` iterator so that nanobind can implement the recommendation from https://docs.python.org/3.14/howto/free-threading-extensions.html#pydict-next The primary goal of ``nb::internal::dict_iterator`` was to be able to write ```cpp nb::dict my_dict = /* ... */; for (auto [k, v] : my_dict) { // .... } ``` This in fact the only associated feature that is explicitly mentioned in the documentation, and this continues to work. However, some undocumented features are lost: - The dictionary iterator is no longer copyable. This is because it must acquire an exclusive lock to the underlying dictionary. - The pre-increment operator ``++dict_it`` (which relied on copying) is gone. Post-increment continues to work, and that is enough for the loop structure mentioned above.
Configuration menu - View commit details
-
Copy full SHA for 0026b83 - Browse repository at this point
Copy the full SHA 0026b83View commit details -
Configuration menu - View commit details
-
Copy full SHA for 29d8834 - Browse repository at this point
Copy the full SHA 29d8834View commit details -
Lock function arguments at compile time (#720)
This commit refactors argument the locking locking so that it occurs at compile-time without imposing runtime overheads. The change applies to free-threaded extensions. Behavior differences compared to the prior approach: - it is no longer possible to do ``nb::arg().lock(false)`` or ``.lock(runtime_determined_value)`` - we no longer prohibit locking self in ``__init__``; changing this would also require restoring ``cast_flags::lock``, and it's not clear that the benefit outweighs the complexity.
Configuration menu - View commit details
-
Copy full SHA for ec77413 - Browse repository at this point
Copy the full SHA ec77413View commit details -
Configuration menu - View commit details
-
Copy full SHA for 53e1e81 - Browse repository at this point
Copy the full SHA 53e1e81View commit details -
Configuration menu - View commit details
-
Copy full SHA for a1a055a - Browse repository at this point
Copy the full SHA a1a055aView commit details