-
-
Notifications
You must be signed in to change notification settings - Fork 31.6k
methodcaller
is not thread-safe (or re-entrant)
#127065
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
Comments
Hmm, actually it looks like a thread safety issue in |
Yeah, I noticed early it wasn't triggering if I called the descriptors directly without going through |
methodcaller
is not thread-safe (or re-entrant)
The `methodcaller` C vectorcall implementation uses an arguments array that is shared across calls. The first argument is modified on every invocation. This isn't thread-safe in the free threading build. I think it's also not safe in general, but for now just disable it in the free threading build.
I think the optimized Line 1661 in 3926842
Most (or all) of our current vectorcall implementations extract out For now, I'm planning to just disable the optimization in the free threading build (#127109), but I don't see an easy way of making it thread-safe, and I think we should consider reverting #107201 in 3.13 and main. |
…127109) The `methodcaller` C vectorcall implementation uses an arguments array that is shared across calls. The first argument is modified on every invocation. This isn't thread-safe in the free threading build. I think it's also not safe in general, but for now just disable it in the free threading build.
…ild (pythonGH-127109) The `methodcaller` C vectorcall implementation uses an arguments array that is shared across calls. The first argument is modified on every invocation. This isn't thread-safe in the free threading build. I think it's also not safe in general, but for now just disable it in the free threading build. (cherry picked from commit f83ca69) Co-authored-by: Sam Gross <colesbury@gmail.com>
…uild (GH-127109) (GH-127150) The `methodcaller` C vectorcall implementation uses an arguments array that is shared across calls. The first argument is modified on every invocation. This isn't thread-safe in the free threading build. I think it's also not safe in general, but for now just disable it in the free threading build. (cherry picked from commit f83ca69) Co-authored-by: Sam Gross <colesbury@gmail.com>
I agree this looks like a bug also in the normal build. The issue is hard to trigger in the normal build though, as indeed most vectorcall implementations (including the One option to make the vectorcall implementation thread-safe (and re-entrant) would be to copy the entire A quick benchmark (using the script from #107201) shows there is still a significant performance increase: Current main:
Disable the vectorcall (this is the solution Sam added to the FT build):
Copy
(all benchmarks without PGO and with the normal Python build) @colesbury Is this idea an option for the free-threading build? |
Can you create a PR? I cannot open the link, it takes too long and GitHub displays an error. |
I removed the draft status from the PR (thanks to @colesbury for some good suggestions). Both PR #127109 or reverting #107201 are good options I think (a classic trade-off between performance and added complexity, except that in this case the status quo is not good) |
The function `operator.methodcaller` was not thread-safe since the additional of the vectorcall method in gh-89013. In the free threading build the issue is easy to trigger, for the normal build harder. This makes the `methodcaller` safe by: * Replacing the lazy initialization with initialization in the constructor. * Using a stack allocated space for the vectorcall arguments and falling back to `tp_call` for calls with more than 8 arguments.
The issue has been addressed on main and on 3.13 the optimization has been removed for the free-threading build. I think we can close this issue, unless we would also like to address the issue for 3.13 with the normal build. @Yhg1s Can you decide on 3.13? |
…GH-127746) The function `operator.methodcaller` was not thread-safe since the additional of the vectorcall method in pythongh-89013. In the free threading build the issue is easy to trigger, for the normal build harder. This makes the `methodcaller` safe by: * Replacing the lazy initialization with initialization in the constructor. * Using a stack allocated space for the vectorcall arguments and falling back to `tp_call` for calls with more than 8 arguments.
…ild (python#127109) The `methodcaller` C vectorcall implementation uses an arguments array that is shared across calls. The first argument is modified on every invocation. This isn't thread-safe in the free threading build. I think it's also not safe in general, but for now just disable it in the free threading build.
Bug report
EDIT: edited to clarify that the issue is in the C implementation of
operator.methodcaller
.Originally reported by @ngoldbaum in crate-py/rpds#101
Reproducer
Once every 5-10 runs, the program prints:
The problem is that
operator.methodcaller
is not thread-safe because it modifies thevectorcall_args
, which is shared across calls:cpython/Modules/_operator.c
Lines 1646 to 1666 in 0af4ec3
I think this is generally unsafe, not just for free threading. The
vectorcall
args array needs to be valid for the duration of the call, and it's possible formethodcaller
to be called reentrantly or by another thread while the call is still ongoing.Linked PRs
methodcaller
thread-safe in free threading build #127109methodcaller
thread-safe in free threading build (GH-127109) #127150The text was updated successfully, but these errors were encountered: