Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.3k
gh-129107: make bytearray free-thread safe#129108
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
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.
I'll yield to someone else, but this is one of the things that we probablyshouldn't do with critical sections.bytearray is a hot object--we should keep performance in mind here. A lot (but not all!) ofbytearray isn't prone to deadlocks because it doesn't typically re-enter.
I'm still undecided, but it might be worth borrowing from the FT list implementation for doing it locklessly.
Uh oh!
There was an error while loading.Please reload this page.
tom-pytel commentedJan 21, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
In this I was just going from what I saw in Line 330 ine65a1eb
Though optimizations are of course on the table, first pass is just to get it correct and fix the crashes in the script in the issue for this PR. EDIT: Though list does store whole objects and this stores bytes, so yeah, would be good to hear from someone with domain knowledge here. EDIT: You made me curious so here are some very rough totally unscientific timings to compare (note is VM). TL;DR: Main branch gil disabled: $ ./pythonPython3.14.0a4+experimentalfree-threadingbuild (heads/main:f3980af38b,Jan202025,22:11:16) [GCC11.4.0]onlinuxType"help","copyright","credits"or"license"formoreinformation.>>>importsysconfig;sysconfig.get_config_var('CONFIG_ARGS')"'--enable-optimizations' '--with-lto' '--disable-gil'">>>fromtimeitimporttimeit>>>b=bytearray(b'0')>>>timeit('b[0]',number=1000000000,globals=globals())11.69659708800009>>>timeit('b[0]',number=1000000000,globals=globals())11.63345341299987>>>timeit('b[0]',number=1000000000,globals=globals())11.640422253999986 This PR gil disabled: $ ./pythonPython3.14.0a4+experimentalfree-threadingbuild (heads/fix-issue-129107:832cc05259,Jan202025,22:18:24) [GCC11.4.0]onlinuxType"help","copyright","credits"or"license"formoreinformation.>>>importsysconfig;sysconfig.get_config_var('CONFIG_ARGS')"'--enable-optimizations' '--with-lto' '--disable-gil'">>>fromtimeitimporttimeit>>>b=bytearray(b'0')>>>timeit('b[0]',number=1000000000,globals=globals())14.824142644999938>>>timeit('b[0]',number=1000000000,globals=globals())14.943688319000103>>>timeit('b[0]',number=1000000000,globals=globals())14.88797294799997 Main branch gil enabled: $ ./pythonPython3.14.0a4+ (heads/main:f3980af38b,Jan212025,06:14:12) [GCC11.4.0]onlinuxType"help","copyright","credits"or"license"formoreinformation.>>>importsysconfig;sysconfig.get_config_var('CONFIG_ARGS')"'--enable-optimizations' '--with-lto'">>>fromtimeitimporttimeit>>>b=bytearray(b'0')>>>timeit('b[0]',number=1000000000,globals=globals())10.562217106999924>>>timeit('b[0]',number=1000000000,globals=globals())10.573908387000074>>>timeit('b[0]',number=1000000000,globals=globals())10.467421004000016 This PR gil enabled: $ ./pythonPython3.14.0a4+ (heads/fix-issue-129107:832cc05259,Jan212025,06:35:31) [GCC11.4.0]onlinuxType"help","copyright","credits"or"license"formoreinformation.>>>importsysconfig;sysconfig.get_config_var('CONFIG_ARGS')"'--enable-optimizations' '--with-lto'">>>fromtimeitimporttimeit>>>b=bytearray(b'0')>>>timeit('b[0]',number=1000000000,globals=globals())10.491293710999798>>>timeit('b[0]',number=1000000000,globals=globals())10.446074409000175>>>timeit('b[0]',number=1000000000,globals=globals())10.451200100999813 And just for a sanity check, my system vanilla py 3.10: $pythonPython3.10.12 (main,Nov62024,20:22:13) [GCC11.4.0]onlinuxType"help","copyright","credits"or"license"formoreinformation.>>>importsysconfig;sysconfig.get_config_var('CONFIG_ARGS')"'--enable-shared' '--prefix=/usr' '--libdir=/usr/lib/x86_64-linux-gnu' '--enable-ipv6' '--enable-loadable-sqlite-extensions' '--with-dbmliborder=bdb:gdbm' '--with-computed-gotos' '--without-ensurepip' '--with-system-expat' '--with-dtrace' '--with-system-libmpdec' '--with-wheel-pkg-dir=/usr/share/python-wheels/' 'MKDIR_P=/bin/mkdir -p' '--with-system-ffi' 'CC=x86_64-linux-gnu-gcc' 'CFLAGS=-g -fstack-protector-strong -Wformat -Werror=format-security ' 'LDFLAGS=-Wl,-Bsymbolic-functions -g -fwrapv -O2 ' 'CPPFLAGS=-Wdate-time -D_FORTIFY_SOURCE=2'">>>fromtimeitimporttimeit>>>b=bytearray(b'0')>>>timeit('b[0]',number=1000000000,globals=globals())18.547491659999878>>>timeit('b[0]',number=1000000000,globals=globals())18.55064152900013>>>timeit('b[0]',number=1000000000,globals=globals())18.568128662999925 |
Uh oh!
There was an error while loading.Please reload this page.
I suggest to split this PR into 2:
|
Makes sense, iterator is smaller (and easier to backport?) so will break that out and send it separate up later today and leave this one as the main bytearray? |
Yup, SGTM, ping me for reviews. |
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
@colesbury This PR fixes thread safety of bytearray with critical section; do we want to have lock free reads for this too? |
No, probably not. At least not for now. |
a05433f intopython:mainUh oh!
There was an error while loading.Please reload this page.
robsdedude commentedMar 3, 2025
Thank you very much for the continued efforts 🙇 Are there plans to backport this (and the follow-up PRs) to 3.13? |
As of now there are no plans to backport these. |
Uh oh!
There was an error while loading.Please reload this page.
Most of the work has been wrapping functions that need it in critical sections (one at a time, testing each one). There were some functions which were pointed directly at stringlib methods and needed critical sections, but since stringlib is shared with
strandbytesand those immutable types don't need locks, the stringlib functions were not touched. Instead, they were wrapped in functions which take object locks.There is work left to do, testing and doing the iterator. But starting as it is, this PR passes the test suite (at least on my system and build) as well as fixing the error cases presented in the script in the associated issue.
Functions which were looked at ("
-" means no critical section was needed, otherwise function was fixed in one way or another):Comments and guidance requested.