Python Function calls are really slow

ぃ、小莉子 提交于 2019-12-03 07:32:52

You are comparing apples and pears here. One method does simple assignment, the other calls a function. Yes, function calls will add overhead.

You should strip this down to the bare minimum for timeit:

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

Now all we did was add a function call (foo does the same thing), so you can measure the extra time a function call takes. You cannot state that this is nearly 4 times slower, no, the function call adds a 0.11 second overhead for 1.000.000 iterations.

If instead of a = 5 we do something that takes 0.5 seconds to execute one million iterations, moving them to a function won't make things take 2 seconds. It'll now take 0.61 seconds because the function overhead doesn't grow.

A function call needs to manipulate the stack, pushing the local frame onto it, creating a new frame, then clear it all up again when the function returns.

In other words, moving statements to a function adds a small overhead, and the more statements you move to that function, the smaller the overhead becomes as a percentage of the total work done. A function never makes those statements themselves slower.

A Python function is just an object stored in a variable; you can assign functions to a different variable, replace them with something completely different, or delete them at any time. When you invoke a function, you first reference the name by which they are stored (foo) and then invoke the function object ((arguments)); that lookup has to happen every single time in a dynamic language.

You can see this in the bytecode generated for a 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 LOAD_GLOBAL opcode looks up the name (foo) in the global namespace (basically a hash table lookup), and pushes the result onto the stack. CALL_FUNCTION then invokes whatever is on the stack, replacing it with the return value. RETURN_VALUE returns from a function call, again taking whatever is topmost on the stack as the return value.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!