-
-
Save x42005e1f/44b1e178c4bec96c3d02e9f52729b10e to your computer and use it in GitHub Desktop.
| #!/usr/bin/env cython | |
| # SPDX-FileCopyrightText: 2026 Ilya Egorov <0x42005e1f@gmail.com> | |
| # SPDX-License-Identifier: 0BSD | |
| # cython: freethreading_compatible = True | |
| # cython: subinterpreters_compatible = own_gil | |
| # distutils: extra_compile_args = -DCYTHON_USE_MODULE_STATE=1 | |
| cdef extern from "stdatomic.h" nogil: | |
| cdef enum memory_order: | |
| memory_order_relaxed | |
| char atomic_fetch_add_explicit(char *obj, char arg, memory_order order) | |
| cpdef char fetch_inc(char[:] mem) nogil: | |
| return atomic_fetch_add_explicit(&mem[0], 1, memory_order_relaxed) |
| #!/usr/bin/env python3 | |
| # SPDX-FileCopyrightText: 2026 Ilya Egorov <0x42005e1f@gmail.com> | |
| # SPDX-License-Identifier: 0BSD | |
| import os | |
| import time | |
| from concurrent.futures import ( | |
| InterpreterPoolExecutor, | |
| ProcessPoolExecutor, | |
| ThreadPoolExecutor, | |
| ) | |
| from multiprocessing import RawArray, set_start_method | |
| from _testatomic import fetch_inc | |
| arr = RawArray("B", [0]) | |
| mem = memoryview(arr).cast("B") | |
| def work(mem=None): | |
| if mem is None: # thread | process (fork) | |
| fetch_inc(arr) | |
| else: # subinterpreter | |
| fetch_inc(mem) | |
| def main(): | |
| expected = 0 | |
| for cls in [ | |
| ThreadPoolExecutor, | |
| InterpreterPoolExecutor, | |
| ProcessPoolExecutor, | |
| ]: | |
| start = time.perf_counter() | |
| with cls(n := min(max(4, os.process_cpu_count()), 256)) as executor: | |
| while time.perf_counter() - start < 1: # one second | |
| expected += n | |
| expected %= 256 | |
| if cls is InterpreterPoolExecutor: | |
| futures = [executor.submit(work, mem) for _ in range(n)] | |
| else: | |
| futures = [executor.submit(work) for _ in range(n)] | |
| exceptions = [] | |
| for future in futures: | |
| if future.exception() is not None: | |
| exceptions.append(future.exception()) | |
| if exceptions: | |
| msg = "unhandled errors from workers" | |
| raise BaseExceptionGroup(msg, exceptions) | |
| assert expected == mem[0], f"{expected} != {mem[0]}" | |
| print(f"{cls.__name__}: passed") | |
| if __name__ == "__main__": | |
| set_start_method("fork") | |
| main() |
Interesting, thanks. Perhaps it would be worth including a copyright notice and some information about the changes required by PSF-2.0 for the borrowed files. But overall, I understand the idea.
Interesting, thanks. Perhaps it would be worth including a copyright notice and some information about the changes required by PSF-2.0 for the borrowed files. But overall, I understand the idea.
I'll be sure to update the license a little later.
After seeing my old attempts of trying to bridge atomics to cython I think I'm going to make it so that there is a better unified system for atomics vs the one python provides for 3.13+. One of the things that I do not like about python's version is that the code doesn't feel completely natural at all and the functions have some pretty unusual names given. I did have the idea however of making my own version as a C Library that could be a header only that I would call "uatomics.h" meaning unified atomics that could contain proper msvc, gcc & std support. This way the process of binding everything to cython can be a bit easier with the benefit of binding it to other languages for users who end up needing it, an example would be NodeJS.
https://gist.github.com/Vizonex/17bbfe7e6bb6a36d82d0d99217eaa049
Mine was a little bit more detailed even though it would've just been a rewrite of pyatomics. The cyatomics notation was mostly just incase of redefinitions being a problem.