Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork32.1k
GH-132380: Avoid locking in type lookup.#135112
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
Draft
nascheme wants to merge1 commit intopython:mainChoose a base branch fromnascheme:gh-132380-tp-lookup-no-lock
base:main
Could not load branches
Branch not found:{{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline, and old review comments may become outdated.
Draft
Uh oh!
There was an error while loading.Please reload this page.
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
If the type lookup cache (mcache) is missed, do not acquire TYPE_LOCKunless we need to assign a type version. We actually don't need to lockin order to do the MRO attribute lookup.
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading.Please reload this page.
This is a slightly modified version ofGH-132381 but based on the 'main' branch instead of 3.13. I originallyclosedGH-132381 because Sam had some concerns about the approach. However, on re-visting it, I still think this change is worth considering. It helps the non-interned string lookup case and should also help in general due to less contention on TYPE_LOCK.
If the type lookup cache (mcache) is missed, do not acquire TYPE_LOCK unless we need to assign a type version. We actually don't need to lock in order to do the MRO attribute lookup.
This avoids lock contention outlined inGH-132380. Performance results based on running LibCST on the numpy source:
-X gil=1
(multi-process)In a previous version of this PR, Sam was concerned about the addition of the
_PyType_GetMRO()
call, potentially causing refcount contention. I don't think that's a problem since the previous code immediately calledPy_INCREF()
on the mro tuple and so this should make it no worse in that respect.Sam also made the comment:
The lock is only held when assigning the type version. The MRO lookup and cache update are done without a lock. It could happen that we add an entry to the cache with an out-of-date (already stale) type version number. That has the downside of potentially replacing a good entry from the cache with a useless one. However, I think this case is so rare that it doesn't matter in practice and it is more efficient not to handle this case. The replacement is not permanent. The next time the "good" item is looked up, it will be re-added to the cache, replacing the stale entry. So, unless the type version is changing on every lookup, the addition of the stale entry is temporary.
We could handle it explicitly by re-checking the current type version after the
find_name_in_mro()
call but I think that would overall decrease performance. I didn't try benchmarking this though. The cache miss path is already pretty slow so probably it won't hurt much to re-check the version.pyperformance results
This attached script shows a behavioral difference due to this change. Since the type objects are allowed to be mutated while the MRO lookup is happening, you can get an
AttributeError
running this script while in previous versions I don't think that was possible. At least, not without having__hash__
or similar methods that mutate the type objects.race_mro_lookup.py.txt