-
-
Notifications
You must be signed in to change notification settings - Fork 33.1k
Closed
Labels
performancePerformance or resource usagePerformance or resource usagestdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancementA feature request or enhancement
Description
Feature or enhancement
The random module has a bunch of code that binds methods to temporary local variables like:
getrandbits = self.getrandbits
Lines 248 to 253 in 55815a6
getrandbits = self.getrandbits | |
k = n.bit_length() | |
r = getrandbits(k) # 0 <= r < 2**k | |
while r >= n: | |
r = getrandbits(k) | |
return r |
I think this pattern dates back to 2001 (in d7b5e88). I think it was an optimization at one point, but now it's the opposite. Python optimizes method calls (in some sort since 3.7) so it's faster to use:
k = n.bit_length()
r = self.getrandbits(k) # 0 <= r < 2**k
while r >= n:
r = self.getrandbits(k)
return r
Getting rid of this pattern seems to:
- Speed calls like
random.randint()
andrandom.shuffle()
by about 10-15% - Avoid some contention in multithreaded code because we are able to specialize the calls to
LOAD_ATTR_METHOD_WITH_VALUES
1
This came up when looking at a variation of @pfmoore's code snippet: montecarlo.py
Linked PRs
Footnotes
-
I think we should be able avoid contention even with this (anti-)pattern, but I'll write that up in a separate issue. ↩
Metadata
Metadata
Assignees
Labels
performancePerformance or resource usagePerformance or resource usagestdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancementA feature request or enhancement