2013-03-08 24 views
7

Beni Why does Python code run faster in a function? sorusuna yönlendiren bir yorum gördüm. 10**8 şeyler biraz daha hızlı hale getirmek için 10**7 değiştirildi:Python kodunun bir işlevde daha hızlı çalıştığı GERÇEKTEN doğru mu?

(not:

ancak ben çok farklı sonuçlar var, düşünce var ve ben timeit kitaplığı kullanarak kendim denemek düşündüm zaman)

>>> from timeit import repeat 
>>> setup = """ 
def main(): 
    for i in xrange(10**7): 
     pass 
""" 
>>> stmt = """ 
for i in xrange(10**7): 
    pass 
""" 
>>> min(repeat('main()', setup, repeat=7, number=10)) 
1.4399558753975725 
>>> min(repeat(stmt, repeat=7, number=10)) 
1.4410973942722194 
>>> 1.4410973942722194/1.4399558753975725 
1.9 
  • doğru timeit kullandınız mı?
  • Niçin bu sonuçlar birbirinden% 0.1 daha az farklıdır, diğer soruların sonuçları ise yaklaşık% 250 farklıdır?
  • Python'un (Cython gibi) derlenmiş sürümleri CPython kullanırken fark yaratır mı?
  • Sonuçta: bir işlevde Python kodu gerçekten daha hızlı mı, yoksa sadece nasıl çalıştığınıza bağlı mı? Derleyici optimizasyon algoritmalarına gelir.
+1

I (böylece sürümü ve dağıtımı hem (yani normal bu uygulamaya büyük ölçüde bağlıdır düşünüyorum Python vs CPython vb) önemlidir. Ayrıca, sadece doğru bir karşılaştırma için aynı kodu diğer sorudaki gibi (ve aynı şekilde zamanlama) çalıştırmayı denemelisiniz. – Cornstalks

+1

[Bu gönderi] (http://stackoverflow.com/a/11241708/1961486) anlayışlı. – Octipi

+0

Yani, Python'un derlenmiş sürümlerinde (CPython, PyPy, vb.) Önemli gibi görünüyor, ama sade eski vanilyalı Python'da bir fark yaratmıyor! –

cevap

10

Testinizdeki kusur yolu timeit sizin stmt kodunu derler olduğunu. Aslında, aşağıdaki şablon içinde derlenmiş:

template = """ 
def inner(_it, _timer): 
    %(setup)s 
    _t0 = _timer() 
    for _i in _it: 
     %(stmt)s 
    _t1 = _timer() 
    return _t1 - _t0 
""" 

Böylece stmt aslında fastlocals dizi (yani STORE_FAST) kullanılarak, bir fonksiyonu olarak çalışmaktadır. İşte

fonksiyonu f_no_opt idam optimize edilmemiş derlenmiş stmt karşı f_opt olarak söz konusu sizin fonksiyonu ile bir test:

>>> code = compile(stmt, '<string>', 'exec') 
>>> f_no_opt = types.FunctionType(code, globals()) 

>>> t_no_opt = min(timeit.repeat(f_no_opt, repeat=10, number=10)) 
>>> t_opt = min(timeit.repeat(f_opt, repeat=10, number=10)) 
>>> t_opt/t_no_opt 
0.4931101445632647 
+0

Bu harika ve Python'un iç çalışmalarını daha iyi anladığını gösteriyor. Tecrübenizde, bu nasıl kodlanmalıyız (optimizasyon aşamasında)? –

+2

İyi tasarım zaten fonksiyonlar kullanmayı ve global değişkenleri kullanımınızı en aza indirmeyi gerektiriyor, ancak hıza ihtiyaç duyan sıkı döngülerdeki global değişkenlere kesinlikle erişmekten kaçının. Viki'de daha fazla öneri bulabilirsiniz: [PythonSpeed] (http://wiki.python.org/moin/PythonSpeed). – eryksun

1

Tam zamanında derleme yaparken, işlevlerde bulunursa sık kullanılan kod parçalarını tanımlamak çok daha kolaydır.

Verimlilik kazanımları gerçekte gerçekleştirilmekte olan görevlerin niteliğine bağlı olacaktır. Verdiğiniz örnekte, gerçekten yoğun bir şekilde hiçbir şey yapmıyorsunuz, optimizasyon yoluyla verimlilikte kazanç elde etmek için daha az fırsat bırakıyorsunuz.

Diğerlerinin de belirttiği gibi, CPython tam zamanında derleme yapmaz. Ancak, kod derlendiğinde, C derleyicileri bunları daha hızlı yürütür. GCC derleyicisi bu belgenin dışarı

Kontrol: http://gcc.gnu.org/onlinedocs/gcc/Inline.html

+0

Bu, CPython için doğrudur (derlendiği için), fakat vanilya Python için değil, çünkü bu doğru değildir. –

+0

@WesleyBaugh: Bekleyin ... CPython "vanilya" Python ile aynı değil mi? Yoksa "vanilya" python başka bir şey mi? –

+0

CPython herhangi bir optimizasyonu zorlukla yapıyor. Optimizasyonun kapsamı, bazı yararsız yükleri ve depoları ortadan kaldırıyor. CPython'un JIT'i yoktur ve basitçe bir yorumlayıcı olarak bayt kodu yürütür. (Aynı şey, tüm diğer JIT'lerin desteklediği PyPy, IronPython veya Jython gibi diğer birçok uygulama için de geçerli değildir). – nneonneo

İlgili konular