Python function call is very slow

This is mainly to make sure that my methodology is correct, but my main question was what should be checked outside the function, if at all I need to access this function. I know that I know, premature optimization, but in many cases it is the difference between setting the if statement inside a function call to determine if I need to run the rest of the code or put it before the function call. In other words, he makes no effort to do this anyway. Now all checks are mixed between them, and I would like everything to be well and standardized.

The main reason I asked was that the other answers I saw most often referred to timeit, but that gave me negative numbers, so I switched to this:

import timeit import cProfile def aaaa(idd): return idd def main(): #start = timeit.timeit() for i in range(9999999): a = 5 #end = timeit.timeit() #print("1", end - start) def main2(): #start = timeit.timeit() for i in range(9999999): aaaa(5) #end = timeit.timeit() #print("2", end - start) cProfile.run('main()', sort='cumulative') cProfile.run('main2()', sort='cumulative') 

and got it for output

  ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 0.310 0.310 {built-in method exec} 1 0.000 0.000 0.310 0.310 <string>:1(<module>) 1 0.310 0.310 0.310 0.310 test.py:7(main) 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 2.044 2.044 {built-in method exec} 1 0.000 0.000 2.044 2.044 <string>:1(<module>) 1 1.522 1.522 2.044 2.044 test.py:14(main2) 9999999 0.521 0.000 0.521 0.000 test.py:4(aaaa) 

It seems to me that not a function call is 0.31 seconds, but a call takes 1.52 seconds, which is almost 5 times slower. But, as I said, I have negative numbers with a timeout, so I want to make sure that it is actually slow.

Also from what I'm compiling, cause function calls are so slow because python has to look to make sure the function still exists before it can run it or something else? Isn’t there any way to just tell him how ... to assume that everything still exists, so that he does not need to do unnecessary work, which (apparently) slows it down by 5x?

+6
source share
1 answer

Here you compare apples and pears. One method performs a simple assignment, the other calls a function. Yes, function calls will add overhead.

You should disable this to the minimum minimum for timeit :

 >>> import timeit >>> timeit.timeit('a = 5') 0.03456282615661621 >>> timeit.timeit('foo()', 'def foo(): a = 5') 0.14389896392822266 

Now all we have done is add a function call ( foo does the same), so you can measure the extra time that the function calls. You cannot argue that it is almost 4 times slower, no, calling a function adds 0.11 seconds overhead for 1,000,000 iterations.

If instead of a = 5 we do something that takes 0.5 seconds to complete a million iterations, moving them to a function will not force you to take 2 seconds. Now it will take 0.61 seconds, because the function overhead is not growing.

A function call should handle the stack by clicking on it with a local frame, creating a new frame, and then clearing it again when the function returns.

In other words, moving operators to a function adds a little overhead, and the more operators you switch to this function, the less overhead becomes a percentage of the total work done. A function never makes these statements slower.

A Python function is just an object stored in a variable; you can assign functions to another variable, replace them with something completely different, or delete them at any time. When you call a function, you first refer to the name by which they are stored ( foo ), and then call the function object ( (arguments) ); this search must occur every time in a dynamic language.

You can see this in the bytecode generated for the function:

 >>> def foo(): ... pass ... >>> def bar(): ... return foo() ... >>> import dis >>> dis.dis(bar) 2 0 LOAD_GLOBAL 0 (foo) 3 CALL_FUNCTION 0 6 RETURN_VALUE 

The operation code LOAD_GLOBAL looks at the name ( foo ) in the global namespace (basically, searching in a hash table) and pushes the result onto the stack. CALL_FUNCTION then calls everything on the stack, replacing it with the return value. RETURN_VALUE returned from the function call, again taking what is topmost on the stack as the return value.

+29
source

All Articles