3 ms·
AFAIK this is because CPython has to walk the scope up to find the import for every call in your loop, and still applies to python3, right? You can still use th
by winrid 2y ago
AFAIK this is because CPython has to walk the scope up to find the import for every call in your loop, and still applies to python3, right? You can still use the built in min, just create a "closer" reference before your loop for the same speedup:
inline_min = min
while expr:
if inline_min(blah):
- boxed 2y agoThat's not how imports work in python at all. Imports are super imperative operations that first tries to find it in sys.modules, otherwise executes the module and puts the resulting dict in sys.modules. Then it grabs the symbols you asked for and shoves all those symbols into the global dict for the module. It does have to walk the locals and the globals scopes (there are ONLY exactly two scopes in Python!) to find the function, that's true.
- winrid 2y ago> It does have to walk the locals and the globals scopes right, this is what I meant.
- winrid 2y agoAlso I imagine the dict lookup for the module is the slow part? So declaring in local scope just removes a dict lookup? I am by no means a python expert :) I just use it occasionally.
- dfox 2y ago15+ years ago many people would tell you that you should do “from foo import bar” instead of “import foo” to save the overhead inherent in referencing “bar” as “foo.bar”. Well, as almost everything in Python is in the end an dict, the dict implementation is ridiculously optimized (and in some counter-intuitive ways), so if you care about that overhead you probably should not be using (C)Python in the first place. This “everything is a dict” is also a part of why removing GIL is not as straightforward as it would seem.
- winrid 2y agoActually even on a modern CPU that property lookup does add another ~10% penalty. Granted it's like a .1 second difference out of a second runtime for 10m iterations, but it's measurable! Although I wouldn't be using python on those data sizes usually :)
- hansvm 2y agoTIL. Apparently `nonlocal` and closures are implemented with copies, at least for my copy of dis.dis().
- ipsum2 2y agoBenchmark it, it won't be any faster. Using the if statement: Execution time: 0.00648 seconds Using the min function directly: Execution time: 0.02298 seconds Using the min function with an intermediate variable: Execution time: 0.02959 seconds
- necovek 2y agoHow about using the `min` builtin directly over the entire list?
- winrid 2y agoSure, let's benchmark it :) It is consistently around 8% to 15% faster on 3.10.12 and 3.11 for me. On 3.12.5 (latest) I seem to get the same result. https://www.online-python.com/B6AgKW5zod https://www.online-python.com/B6AgKW5zod (please copy the code to your local to not ddos this site :D)
- otteromkram 2y agoI agree with you. It's a weird quirk of Python where localization is more efficient.
- b3orn 2y agoIt makes a slight difference on my system, python 3.12.0 In [1]: def test_1(): ...: i = 10_000_000 ...: r = 0 ...: ...: while i>0: ...: i = i-1 ...: r += min(i, 500) ...: ...: return r In [2]: def test_2(): ...: i = 10_000_000 ...: r = 0 ...: local_min = min ...: ...: while i>0: ...: i = i-1 ...: r += local_min(i, 500) ...: ...: return r In [3]: %timeit -n 1 -r 10 test_1() 2.14 s ± 58.4 ms per loop (mean ± std. dev. of 10 runs, 1 loop each) In [4]: %timeit -n 1 -r 10 test_2() 1.94 s ± 47.8 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)