Другим фактором может быть «подготовка»/настройка, выполняемая до того, как вызывается TaskA
. Возможно, что в f1
вы сделали это один раз перед циклом for
, а затем это делается в f3
, поэтому он вызывается для каждого x in X
от f2
, а не только один раз в начале. Без реального кода трудно сказать.
Что касается потенциальной сложности вызова f3
за каждые x
, маловероятно, что это является причиной 10-кратной медлительности.
Только в упрощенном примере с pass
мы видим это поведение. Давайте эти 3 плохие версии f1
, f2
и f3
:
>>> def f1():
... for x in X:
... pass
...
>>> def f2():
... for x in X:
... f3()
...
>>> def f3():
... pass
...
Используя dis
, вот что байт-код выглядит для f1
:
>>> dis.dis(f1)
2 0 SETUP_LOOP 14 (to 17)
3 LOAD_GLOBAL 0 (X)
6 GET_ITER
>> 7 FOR_ITER 6 (to 16)
10 STORE_FAST 0 (x)
3 13 JUMP_ABSOLUTE 7
>> 16 POP_BLOCK
>> 17 LOAD_CONST 0 (None)
20 RETURN_VALUE
... против f2
:
>>> dis.dis(f2)
2 0 SETUP_LOOP 21 (to 24)
3 LOAD_GLOBAL 0 (X)
6 GET_ITER
>> 7 FOR_ITER 13 (to 23)
10 STORE_FAST 0 (x)
3 13 LOAD_GLOBAL 1 (f3)
16 CALL_FUNCTION 0
19 POP_TOP
20 JUMP_ABSOLUTE 7
>> 23 POP_BLOCK
>> 24 LOAD_CONST 0 (None)
27 RETURN_VALUE
Те же, что и у CALL_FUNCTION
и POP_TOP
. Тем не менее, они очень разные с timeit
:
>>> X = range(1000) # [0, 1, 2, ...999]
>>>
>>> import timeit
>>> timeit.timeit(f1)
10.290941975496747
>>> timeit.timeit(f2)
81.18860785875617
>>>
Теперь это ое время, но не потому, что вызов функции является медленно но потому, что ничего не делать, но pass
в f1
-х для петли очень быстро, особенно когда вызывает функцию каждый раз, что затем ничего не делает. Так что, надеюсь, вы были не, используя их в качестве примеров, чтобы узнать/удивить почему.
Теперь, если вы на самом деле сделать что-то в задаче, как говорят x * x
тогда вы увидите разницу времени/производительность между двумя становится меньше:
>>> def f1():
... for x in X:
... _ = x*x
...
>>> def f2():
... for x in X:
... _ = f3(x) # didn't pass in `x` to `f3` in the previous example
...
>>> def f3(x):
... return x*x
...
>>> timeit.timeit(f1)
38.76545268807092
>>> timeit.timeit(f2)
113.72242594670047
>>>
Теперь это только 2.9x время.Это не вызов функции, который вызывает медленность (да, есть некоторые накладные расходы), но и то, что вы делаете в этой функции vs pass
, что имеет значение для общего времени.
Если заменить _ = x * x
с print x * x
в обоих местах, что вполне «медленные», и только с X = range(5)
:
>>> timeit.timeit(f1, number=10000)
3.640433839719143
>>> timeit.timeit(f2, number=10000)
3.6921612171574765
А теперь гораздо меньше различий в их исполнении.
Так что сделайте реальную проверку с помощью реального кода, а не просто с помощью простого анализа псевдокода. Пустые вызовы могут появляться быстрее, но эти накладные расходы очень малы по сравнению с более медленными вещами, что делает код в функциях.
Ну, очевидно, этот псевдокод медленный, потому что вы используете ужасный интерпретатор псевдокода ... Вы считали, что вместо этого вы отправляете ** фактический ** код? –
Вы даете нам код, где вызов функции буквально является единственной разницей. Единственный вывод, к которому мы можем прийти, это «Функциональные вызовы медленные». Тот факт, что вызовы функций не являются (заметно) медленными в реальности, показывает, что вы фактически не опубликовали соответствующий фрагмент кода. Я предлагаю вам попробовать ['cProfile.run ('f2()')'] (https://docs.python.org/2/library/profile.html) –