2016-07-15 12 views
-1

2つの関数を実行します。どちらも命令を実行するためのfor-loopを持っています。どちらの関数も同じタスクを実行しますが、時間がかかります。ループ内のコードとコード内のスクリプトの実行時間の差

機能1は実行され、自己完結型で、TaskAを実行します。関数2は、一般関数1として実行する限り、10倍を取るない理由

f1: 
    For x in X: 
    do task a 

機能2を実行し、コールは3機能3を行うTaskA

f2: 
    For x in X: 
    call function 3 
f3: 
    do task a 

ファンクション?

編集:以前の表現は混乱しています。

+3

あなたが恐ろしい擬似コードインタープリタを使用しているので、明らかにこの擬似コードは遅いです...実際に**コードを投稿することを考えましたか? –

+0

あなたは関数呼び出しが文字通り唯一の違いであるコードを私たちに与えています。おそらく到達できる唯一の結論は、「関数呼び出しは遅い」ということです。関数呼び出しが(顕著に)遅くないという事実は、実際にコードの関連部分を投稿していないことを示しています。 ['cProfile.run( 'f2()')'](https://docs.python.org/2/library/profile.html) –

答えて

1

もう1つの要因は、TaskAが呼び出される前に実行される「準備」/セットアップです。可能であればf1forループの前に1回行ってからf3で完了し、x in Xからf2に1回だけではなく1回呼び出される可能性があります。実際のコードがなければ、言うことは難しいです。

xごとにf3を呼び出す潜在的な複雑さは、それが10倍の遅さの原因であるとは考えられません。

passの簡略化された例でのみ、この現象があります。ここでのバイトコードがf1のための次のようになります、disを使用して

>>> def f1(): 
... for x in X: 
...  pass 
... 
>>> def f2(): 
... for x in X: 
...  f3() 
... 
>>> def f3(): 
... pass 
... 

>>> 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 
のは f1f2f3のこれら3つの悪いのバージョンを見てみましょう

これらは、を除いてほぼ同じです10およびPOP_TOP。しかし、彼らはtimeitと非常に異なっている:

>>> X = range(1000) # [0, 1, 2, ...999] 
>>> 
>>> import timeit 
>>> timeit.timeit(f1) 
10.290941975496747 
>>> timeit.timeit(f2) 
81.18860785875617 
>>> 

今では時間の8倍だがない関数を呼び出すことは遅いあるので、しかし、forループf1年代にpassが、何もしないことは、特に、非常に高速であるため、 を呼び出すと、毎回関数が呼び出され、何もしません。だからうまくいけばではないこれらを例として使って/ wonderを調べる理由。今

x * xはその後、次の2つの間のタイミング/パフォーマンスの差が小さくなって表示されます言うようにあなたが実際には、タスクで何かをすれば:今では唯一の2.9x

>>> 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 
>>> 

時間。遅れを引き起こす関数呼び出し(ある程度のオーバーヘッドがあります)だけでなく、関数内で何をしているのかは、全体の時間に違いをもたらすpassです。

あなたはかなりの「遅い」、そしてちょうどX = range(5)である、両方の場所でprint x * x_ = x * xを交換する場合:

>>> timeit.timeit(f1, number=10000) 
3.640433839719143 
>>> timeit.timeit(f2, number=10000) 
3.6921612171574765 

そして今、彼らのパフォーマンスのあまり違いがあります。

単純な擬似コード分析だけでなく、実際のコードで実際のチェックを行います。空の呼び出しは速く表示されるかもしれませんが、そのオーバーヘッドは実際には遅いものののコードでは機能しません。

+0

私は本当にあなたの詳細な分析に感謝します。これは私が探していたものです。申し訳ありませんが、一般的にこのボードで質問するにはあまりにも多くの場合、私は気づいていませんでした。 – Angus

+0

問題は実際のコードがないあなたのような特定の質問をすることは本当に答えが難しいことです。だから私はあなたがそのような大きなパフォーマンスの違いを見た理由を説明するランダムな例を作りました。 – aneroid

関連する問題