Neden Python 3 * ' den x**4.0 daha hızlı ?x**4
Python 3 intnesneleri, keyfi bir boyutu desteklemek için tasarlanmış tam teşekküllü bir nesnedir; Bu nedenle, C seviyesinde bu şekilde ele alınırlar (tüm değişkenlerin nasıl PyLongObject *tür olarak bildirildiğine bakın long_pow). Bu, üslerini çok daha zor ve sıkıcı hale getirir, çünkü ob_digitdeğerini gerçekleştirmek için kullandığı dizi ile oynamanız gerekir. ( Cesurlar için kaynak. - Bkz . Daha fazla bilgi için Python'daki büyük tamsayılar için bellek ayırmayı anlamaPyLongObject .)
Piton floatamaçları, tam tersine, transforme edilebilir bir C double(kullanarak türü PyFloat_AsDouble) ve işlemler yapılabilir , bu doğal türleri kullanarak . Bu harika alakalı kenar-durumlar için kontrol ettikten sonra, bu için Python verir, çünkü platformları kullanabilirsinizpow ( C'ler powolduğunu ) fiili üs ele:
/* Now iv and iw are finite, iw is nonzero, and iv is
* positive and not equal to 1.0. We finally allow
* the platform pow to step in and do the rest.
*/
errno = 0;
PyFPE_START_PROTECT("pow", return NULL)
ix = pow(iv, iw);
nerede ivve iwbizim orijinal PyFloatObjectC olarak doubles.
Değeri 2.7.13için: Benim için Python 2~3daha hızlı bir faktördür ve ters davranışı gösterir.
Önceki gerçek de Python 2 ve 3 arasındaki tutarsızlığı açıklıyor , bu yüzden ilginç olduğu için bu yorumu da ele alacağımı düşündüm.
Python 2'de, Python 3'teki nesneden intfarklı olan eski nesneyi kullanıyorsunuz int( int3.x'teki tüm nesneler türdedir PyLongObject). Python 2'de, nesnenin değerine (veya sonek kullanırsanız L/l) bağlı bir ayrım vardır :
# Python 2
type(30) # <type 'int'>
type(30L) # <type 'long'>
<type 'int'>Burada gördüğünüz aynı şeyi yapar floatler yapmak güvenle bir C dönüştürülmüş olur, long üs alma üzerine yapılır ( int_powbunu yapabiliyorsa, böylece aynı zamanda bir kayıt onları koymak için derleyici ipuçları verebilir bir fark yaratmak) :
static PyObject *
int_pow(PyIntObject *v, PyIntObject *w, PyIntObject *z)
{
register long iv, iw, iz=0, ix, temp, prev;
/* Snipped for brevity */
bu iyi bir hız kazancı sağlar.
Durgun s'ların <type 'long'>s ile karşılaştırıldığında ne kadar olduğunu görmek için <type 'int'>, xadı longPython 2'deki bir çağrıda tamamladıysanız (esas long_powolarak Python 3'teki gibi kullanmaya zorlarsanız), hız kazancı kaybolur:
# <type 'int'>
(python2) ➜ python -m timeit "for x in range(1000):" " x**2"
10000 loops, best of 3: 116 usec per loop
# <type 'long'>
(python2) ➜ python -m timeit "for x in range(1000):" " long(x)**2"
100 loops, best of 3: 2.12 msec per loop
Not alın, bu bir pasajı dönüşümleri olsa intiçin long(@pydsinger tarafından sivri out gibi) diğer yaptığı, bu döküm yavaşlamanın arkasında katkıda güç değildir. Uygulamasıdır long_pow. (İfadeleri yalnızca long(x)görmek için zamanlayın).
[...] döngü dışında olmaz. [...] Bunun hakkında bir fikrin var mı?
Bu, sabitleri sizin için katlayan CPython'un gözetleme deliği optimize edicisidir. Her iki durumda da aynı kesin zamanlamaları elde edersiniz, çünkü üstelimin sonucunu bulmak için gerçek bir hesaplama yoktur, sadece değerlerin yüklenmesi:
dis.dis(compile('4 ** 4', '', 'exec'))
1 0 LOAD_CONST 2 (256)
3 POP_TOP
4 LOAD_CONST 1 (None)
7 RETURN_VALUE
Özdeş bayt kodu, '4 ** 4.'tek fark int yerine LOAD_CONSTfloat yükler olmasıdır :256.0256
dis.dis(compile('4 ** 4.', '', 'exec'))
1 0 LOAD_CONST 3 (256.0)
2 POP_TOP
4 LOAD_CONST 2 (None)
6 RETURN_VALUE
Yani zamanlar aynı.
* Yukarıdakilerin tümü sadece Python'un referans uygulaması olan CPython için geçerlidir. Diğer uygulamalar farklı performans gösterebilir.