28

クラスの作成は、クラスのインスタンス化よりもはるかに遅いことがわかりました。

>>> from timeit import Timer as T
>>> def calc(n):
...     return T("class Haha(object): pass").timeit(n)

<<After several these 'calc' things, at least one of them have a big number, eg. 100000>>

>>> calc(9000)
15.947055101394653
>>> calc(9000)
17.39099097251892
>>> calc(9000)
18.824054956436157
>>> calc(9000)
20.33335590362549

ええ、9000クラスの作成には16秒かかり、その後の呼び出しではさらに遅くなります。

この:

>>> T("type('Haha', b, d)", "b = (object, ); d = {}").timeit(9000)

同様の結果が得られます。

しかし、インスタンス化は影響を受けません。

>>> T("Haha()", "class Haha(object): pass").timeit(5000000)
0.8786070346832275

1秒未満で5000000インスタンス。

何がこの作品をこれほど高価なものにしているのでしょうか?

そして、なぜ作成プロセスが遅くなるのですか?

編集:

再現方法:

新しいPythonプロセスを開始します。最初のいくつかの「calc(10000)」は、私のマシンで0.5の数値を示します。そして、いくつかのより大きな値calc(100000)を試してみてください。これは、10秒で終了することはできず、中断します。calc(10000)は、15秒を与えます。

編集:

追加の事実:

'calc'が遅くなった後にgc.collect()を実行すると、最初は' normal'の速度を得ることができますが、その後の呼び出しではタイミングが長くなります。

>>> from a import calc
>>> calc(10000)
0.4673938751220703
>>> calc(10000)
0.4300072193145752
>>> calc(10000)
0.4270968437194824
>>> calc(10000)
0.42754602432250977
>>> calc(10000)
0.4344758987426758
>>> calc(100000)
^CTraceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "a.py", line 3, in calc
    return T("class Haha(object): pass").timeit(n)
  File "/usr/lib/python2.7/timeit.py", line 194, in timeit
    timing = self.inner(it, self.timer)
  File "<timeit-src>", line 6, in inner
KeyboardInterrupt
>>> import gc
>>> gc.collect()
234204
>>> calc(10000)
0.4237039089202881
>>> calc(10000)
1.5998330116271973
>>> calc(10000)
4.136359930038452
>>> calc(10000)
6.625348806381226
4

4 に答える 4

32

これはあなたに直感を与えるかもしれません:

>>> class Haha(object): pass
...
>>> sys.getsizeof(Haha)
904
>>> sys.getsizeof(Haha())
64

クラス オブジェクトは、そのクラスのインスタンスよりもはるかに複雑で高価な構造です。

于 2012-04-09T11:37:14.663 に答える
10

次の機能の簡単な説明:

def a():
    class Haha(object):
         pass



def b():
    Haha()

与えます:

2           0 LOAD_CONST               1 ('Haha')
            3 LOAD_GLOBAL              0 (object)
            6 BUILD_TUPLE              1
            9 LOAD_CONST               2 (<code object Haha at 0x7ff3e468bab0, file "<stdin>", line 2>)
            12 MAKE_FUNCTION            0
            15 CALL_FUNCTION            0
            18 BUILD_CLASS         
            19 STORE_FAST               0 (Haha)
            22 LOAD_CONST               0 (None)
            25 RETURN_VALUE        

2           0 LOAD_GLOBAL              0 (Haha)
            3 CALL_FUNCTION            0
            6 POP_TOP             
            7 LOAD_CONST               0 (None)
            10 RETURN_VALUE        

によると。

見た目では、クラスを作成するときに単純に多くのことを行います。クラスを初期化し、辞書に追加する必要がありますが、場合はHaha()関数を呼び出すだけです。

お気づきのように、ガベージ コレクションの速度が遅すぎると、再び処理速度が上がります。Marcin 氏は、これはおそらくメモリの断片化の問題であると言っています。

于 2012-04-09T11:40:17.113 に答える
3

そうではありません:あなたの不自然なテストだけがクラスの作成が遅いことを示しています。実際、@Veedrac が彼の回答で示しているように、この結果はガベージ コレクションを無効にする時間のアーティファクトです。

反対票を投じる人:クラスの作成が遅い不自然な例を教えてください。

いずれにせよ、タイミングはその時点でのシステムの負荷の影響を受けます。それらは、ほぼ同時に実行される比較にのみ役立ちます。9000クラスの作成で約0.5秒かかります。実際、繰り返し実行しても、ideone では約 0.3 秒です: http://ideone.com/Du859。上昇トレンドすらありません。

したがって、要約すると、あなたのコンピューターでは他のコンピューターよりもはるかに遅く、他のコンピューターで繰り返しテストを行っても上昇傾向はありません (元の主張によると)。おそらくプロセスが大量のメモリを消費するため、膨大な数のインスタンス化をテストすると、速度が低下することが示されます。大量のメモリを割り当てるとプロセスが遅くなることを示しました。素晴らしい。

その完全なイデオン コード:

from timeit import Timer as T
def calc(n):
return T("class Haha(object): pass").timeit(n)

for i in xrange(30):
print calc(9000)
于 2012-04-09T11:36:16.537 に答える