SORU
25 Kasım 2011, Cuma


Neden geri başka yavaştır erken?

Bu nedenle 30 ** bir soru.Düzenleme:bu soru zaten OP the same question, ama bunun farkında olduğumu sormak için ona yazdım kodu kullanılmış gibi görünüyor. Özür dilerim. Cevaplar verilir farklı olsa da!

Büyük ölçüde fark ettim:

>>> def without_else(param=False):
...     if param:
...         return 1
...     return 0
>>> def with_else(param=False):
...     if param:
...         return 1
...     else:
...         return 0
>>> from timeit import Timer as T
>>> T(lambda : without_else()).repeat()
[0.3011460304260254, 0.2866089344024658, 0.2871549129486084]
>>> T(lambda : with_else()).repeat()
[0.27536892890930176, 0.2693932056427002, 0.27011704444885254]
>>> T(lambda : without_else(True)).repeat()
[0.3383951187133789, 0.32756996154785156, 0.3279120922088623]
>>> T(lambda : with_else(True)).repeat()
[0.3305950164794922, 0.32186388969421387, 0.3209099769592285]

...ya da diğer bir deyişle: else fıkra if durumu tetikleyen olmanın hızlı olursa olsun sahip veya değil.

Farklı bayt kodunu iki tarafından oluşturulan ilgisi var sanırım, ama kimseye/detaylar teyit edebilir?

DÜZENLEME:Herkes benim sistemi hakkında biraz bilgi vermek yararlı olabileceğini düşündüm bu yüzden benim zamanlamaları üretiyor olması gibi görünüyor. Varsayılan python yüklü 11.10 64 bit Ubuntu koşuyorum. python aşağıdaki sürüm bilgileri oluşturur:

Python 2.7.2  (default, Oct  4 2011, 20:06:09) 
[GCC 4.6.1] on linux2

Burada demontaj Python 2.7: sonuçları

>>> dis.dis(without_else)
  2           0 LOAD_FAST                0 (param)
              3 POP_JUMP_IF_FALSE       10

  3           6 LOAD_CONST               1 (1)
              9 RETURN_VALUE        

  4     >>   10 LOAD_CONST               2 (0)
             13 RETURN_VALUE        
>>> dis.dis(with_else)
  2           0 LOAD_FAST                0 (param)
              3 POP_JUMP_IF_FALSE       10

  3           6 LOAD_CONST               1 (1)
              9 RETURN_VALUE        

  5     >>   10 LOAD_CONST               2 (0)
             13 RETURN_VALUE        
             14 LOAD_CONST               0 (None)
             17 RETURN_VALUE        

CEVAP
25 Kasım 2011, Cuma


Bu yalnızca bir tahmin olduğunu ve doğru olup olmadığını kontrol etmek için kolay bir yol bulamadım, ama senin için bir teorim var.

Kodunuzu denedim ve aynı sonuçları without_else() sürekli with_else() biraz daha yavaştır

>>> T(lambda : without_else()).repeat()
[0.42015745017874906, 0.3188967452567226, 0.31984281521812363]
>>> T(lambda : with_else()).repeat()
[0.36009842032996175, 0.28962249392031936, 0.2927151355828528]
>>> T(lambda : without_else(True)).repeat()
[0.31709728471076915, 0.3172671387005721, 0.3285821242644147]
>>> T(lambda : with_else(True)).repeat()
[0.30939889008243426, 0.3035132258429485, 0.3046679117038593]

Bayt kodu aynı olduğunu düşünürsek, tek fark fonksiyon adıdır. Özellikle zamanlama testi genel adı üzerinde arama yapar. without_else() yeniden adlandırma deneyin ve farkı kaybolur:

>>> def no_else(param=False):
    if param:
        return 1
    return 0

>>> T(lambda : no_else()).repeat()
[0.3359846013948413, 0.29025818923918223, 0.2921801513879245]
>>> T(lambda : no_else(True)).repeat()
[0.3810395594970828, 0.2969634408842694, 0.2960104566362247]

Benim tahminim without_else globals() başka bir şey ile karma bir çarpışma olduğu genel ad arama biraz daha yavaş.

Edit: 7 veya 8 tuşu ile bir sözlük muhtemelen 32 yuvası var, buna dayanarak without_else __builtins__ ile karma bir çarpışma vardır:

>>> [(k, hash(k) % 32) for k in globals().keys() ]
[('__builtins__', 8), ('with_else', 9), ('__package__', 15), ('without_else', 8), ('T', 21), ('__name__', 25), ('no_else', 28), ('__doc__', 29)]

Karma nasıl çalıştığını açıklamak için:

__builtins__ modül tablo boyutu azaltan -1196389688 dosyalar (32) Tablo #8 yuvasına saklanır anlamına gelir.

without_else 32 modül azaltan 505688136 için karma bir çarpışma var 8. Bu Python gidermek için hesaplar:

İle başlayan:

j = hash % 32
perturb = hash

Ücretsiz bir yuva bulana kadar bu işlemi tekrarlayın:

j = (5*j)   1   perturb;
perturb >>= 5;
use j % 2**i as the next table index;

bir sonraki dizini olarak kullanmak için 17 verir. Neyse ki bu döngü sadece bir kez tekrarlar çok özgür.

Tabloya her sonda bunlardan birini bulabilirsiniz:

  • Yuva boş, sondaj durur ve biz biliyoruz bu durumda. değeri tablo değil.

  • Yuva kullanılmayan ama bu durumda deneyin gidiyoruz eskiden yukarıdaki esaslara göre sonraki değer.

  • Yuvasına tam ama tam karma değeri tabloda saklanmaz. (o da ne arıyoruz anahtarının karma olarak aynı __builtins__ vs without_else) durumunda olur.

  • Dolmuştur ve tam olarak istediğimiz karma değeri vardır, o zaman Python eğer anahtar ve arıyoruz nesne olup olmadığını denetler aynı nesne, bu durumda, çünkü kısa dizeleri olacak (hangi aynı tanımlayıcılar kullanmak çok staj vardır tanımlayıcıları olabilir dize aynı).

  • Nihayet dolmuştur, karma tam olarak uyuşuyor, ama anahtarlar aynı nesne değildir, o zaman ve yalnızca o zaman Python çalışacağız eşitlik karşılaştırılması. Bu nispeten yavaş, ama adı aramaları durumunda aslında olmamalı.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • New Challenger - Game Reviews

    New Challeng

    20 Temmuz 2006
  • NPR

    NPR

    22 NİSAN 2006
  • Slave Boy Films - Fandom from a Galaxy Far Far Away

    Slave Boy Fi

    12 HAZİRAN 2009