python vs bc 6 ^ 6 ^ 6 değerlendirmesinde


29

İfadeyi 6^6^6kullanarak pythonve bcayrı olarak değerlendiriyorum .

Python dosyasının içeriği print 6**6**6. Yürütdüğümde time python test.pyçıktıyı alıyorum

real        0m0.067s
user        0m0.050s
sys         0m0.011s

Ve sonra time echo 6^6^6 | bcbana aşağıdaki çıktıyı veren emri yerine getirdim

real        0m0.205s
user        0m0.197s
sys         0m0.005s

Bu sonuçlardan, python ve bc tarafından alınan sys süresinin sırasıyla 11 ms ve 5 ms olduğu açıktır. Bc komutu sys zaman düzeyinde piton performans sergilemiştir ancak söz konusu olduğunda kullanıcı ve gerçek zamanlı piton neredeyse 4 kat daha hızlı bc daha oldu . Orada neler olmuş olabilir. Bu tür süreçlere öncelik vermedim. Bu durumu anlamaya çalışıyorum.


Yani, sys bileşeninin yalnızca yüklenecek süreyi verdiği ve çalışma zamanının çıktının kullanıcı bileşeninde verileceği anlamına mı geliyorsunuz?
ganessh

Gerçekten emin değilim, bu yüzden bir yorum yazdım. Bu sadece bir tahmin.
terdon

7
echo | bcboru nedeniyle bir alt kabuk başlatmayı içerir - bu da fazladan kullanıcı zamanınızın bir kısmının geldiği yer. Bunu adil bir test yapmak için python betiğinin stdin'den okuması gerekir time echo 6**6**6 | whatever.py.
goldilocks

1
Komut satırını bir betiğe koymayı tercih ederim ve bunun çalışmasını zamanladım. Veya kullanın echo 6^6^6 | time bc.
daniel kullmann

1
Yan not: python'da 6**6**6ifade aslında derleme zamanında hesaplanır . Ancak dosyayı bir modülden içe aktarmak yerine doğrudan başlattığınızdan, bunun önemi yoktur. Farkı 10**12345678bir a.pydosyaya koymak ve etkileşimli tercümandan almaya çalışın. Ardından tercümanı kapatın, yeniden başlatın ve atekrar içe aktarın . İlk kez gözle görülür miktarda zaman alması gerekir (çünkü python modülü .pyc
derler

Yanıtlar:


25

Python başlangıçta çok sayıda dosya alır:

% python -c 'import sys; print len(sys.modules)'
39

Bunların her biri, bir Python dosyasını açmak için daha fazla sayıda deneme yapılmasını gerektirir, çünkü bir modül tanımlamanın birçok yolu vardır:

% python -vv -c 'pass'
# installing zipimport hook
import zipimport # builtin
# installed zipimport hook
# trying site.so
# trying sitemodule.so
# trying site.py
# trying site.pyc
# trying /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site.so
# trying /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/sitemodule.so
# trying /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site.py
# /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site.pyc matches /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site.py
import site # precompiled from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site.pyc
# trying os.so
# trying osmodule.so
# trying os.py
# trying os.pyc
# trying /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.so
# trying /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/osmodule.so
# trying /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.py
# /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc matches /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.py
import os # precompiled from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc
    ...

Yerleşik olanlar dışında her "denemek" bir os seviyesi / sistem çağrısı gerektirir ve her "içe aktarma" yaklaşık 8 "denemek" iletisini tetikler. (Bunu zipimport kullanarak azaltmanın yolları vardı ve PYTHONPATH'nizdeki her yol için başka bir arama yapmanız gerekebilir.)

Bu, Python'un makineme başlamadan önce neredeyse 200 stat sistem çağrısı olduğu ve "zamanın", "kullanıcı" yerine "sys" a atadığı anlamına gelir, çünkü kullanıcı programı sistemde bir şeyler yapmayı beklemektedir.

Karşılaştırma yapmak gerekirse ve terdon'un dediği gibi "bc" başlangıç ​​maliyetinin o kadar yüksek değil. Dtruss çıktısına baktığımda (Linux tabanlı bir işletim sistemi için bir Mac'im var; "strace"), bc'nin birkaç paylaşılan yükleme dışında kendi açık () veya stat () sistem çağrılarını yapmadığını görüyorum. kütüphaneler başlangıçtır, tabii ki Python da öyle. Ek olarak, Python'un bir şeyi işlemeye hazır olmadan önce okunacak daha fazla dosyası var.

Diski beklemek yavaş.

Aşağıdakileri yaparak Python'un başlangıç ​​maliyetini anlayabilirsiniz:

time python -c pass

Makinemde 0.032s var, 'baskı 6 ** 6 ** 6' 0.072s, bu nedenle başlangıç ​​maliyeti toplam sürenin 1 / 2'si ve hesaplama + ondalık için dönüştürme diğer yarısı. Süre:

time echo 1 | bc

0,005 saniye sürer ve "6 ^ 6 ^ 6" 0,144 saniye sürer; bu nedenle bc'nin üssü, başlaması 7 kat daha hızlı olmasına rağmen Python'dan 4 kat daha yavaş gerçekleşir.


4
Oradaki kurşunu gömdün. Bitiş bitini en üste taşımak isteyebilirsiniz.
Riking

Sadece benim makinede dışarı çıkar: Zaman piton -c 0m0.025s 'pas', zaman piton -c '6 yazdırmak 6 piton -c' x = 6 0m0.087s ama zaman 6 ' 6 Yani 6' 0m0.028s en hakkındaki zaman büyük sayıyı çıkarıyor.
Steve Barnes

Evet, 10 tabanına dönüştürme, basamak sayısında ikinci dereceden zaman alır. Aşırı bir durum olarak, daha büyük Mersenne astarlarından birini basmayı deneyin. Hesaplaması çok hızlı, ancak 10 tabanına yazdırmak çok zaman alıyor
Andrew Dalke

11

SO hakkında farklı alanları açıklayan güzel bir cevap buldum :

  • Gerçek duvar saati zamanı - aramanın başlangıcından sonuna kadar olan zaman. Bu, diğer işlemler tarafından kullanılan zaman dilimleri ve işlemin harcadığı zamanlar da dahil olmak üzere geçen zamandır (örneğin, G / Ç'nin tamamlanmasını bekliyorsa).

  • Kullanıcı, işlem sırasında kullanıcı modu kodunda (çekirdeğin dışında) harcanan CPU zamanıdır. Bu sadece işlemin yürütülmesinde kullanılan gerçek CPU zamanıdır. Diğer işlemler ve işlemin harcandığı zaman engelleniyor bu sayıya sayılmaz.

  • Sys, işlem sırasında çekirdekte harcanan CPU zamanı miktarıdır. Bu, hala kullanıcı alanında çalışan kütüphane kodunun aksine, sistem çağrılarında harcanan CPU zamanının çekirdek içinde yürütülmesi anlamına gelir. 'Kullanıcı' gibi, bu yalnızca işlem tarafından kullanılan CPU zamanıdır. Çekirdek modunun (ayrıca 'denetleyici' modu olarak da bilinir) ve sistem çağrı mekanizmasının kısa bir açıklaması için aşağıya bakın.

Bu nedenle, kendi örneğinizde, python sürümü, tamamlanması gereken gerçek zaman bakımından daha hızlıdır. Bununla birlikte, python yaklaşımı çekirdek uzayında daha fazla zaman harcar ve çekirdek fonksiyonlarını çağırır. bcKomut çekirdek alanının esasen hiçbir zaman harcıyor ve tüm 's zaman muhtemelen iç çalışan, kullanıcı uzayında harcanmaktadır bckodu.

Bu sizin için hiçbir şey ifade etmiyor, gerçekten önemsediğiniz tek şey, realkomutun başlatılması ile çıktısının alınması arasında geçen gerçek zamandır.

Ayrıca, bu küçük farklılıkların sabit olmadığını, ayrıca sisteminizin yüküne bağlı olacağını ve komutu her çalıştırdığınızda da değişeceğini unutmayın:

$ for i in {1..10}; do ( time python test.py > /dev/null ) 2>&1; done | grep user
user    0m0.056s
user    0m0.052s
user    0m0.052s
user    0m0.052s
user    0m0.060s
user    0m0.052s
user    0m0.052s
user    0m0.056s
user    0m0.048s
user    0m0.056s

$ for i in {1..10}; do ( time echo 6^6^6 | bc > /dev/null ) 2>&1; done | grep user
user    0m0.188s
user    0m0.188s
user    0m0.176s
user    0m0.176s
user    0m0.172s
user    0m0.176s
user    0m0.180s
user    0m0.172s
user    0m0.172s
user    0m0.172s

10

Bunu başka bir bakış açısıyla açıklayacağım.

Adil olmak gerekirse bc, diskten bir şey okumak zorunda olmadığından ve sadece blob / binary'lerine ihtiyaç duyduğundan, python bir dizi modülü almak + dosyayı okumak zorunda kaldığından avantajlıdır. Bu yüzden testiniz önyargılı olabilir bc. Aslında test etmek kullanmanız gereken bc -q fileyerde filebulunur:

6^6^6
quit

Bunu değiştirmek, kullanım süresini değiştirdi echo:

bc  0.33s user 0.00s system 80% cpu 0.414 total

Dosyayı kullanmak için:

bc -q some  0.33s user 0.00s system 86% cpu 0.385 total

(daha büyük farklılıkları fark etmek için terdon yöntemini kullanmanız gerekecek, ancak en azından biz olduklarını biliyoruz)

Şimdi, python açısından bakıldığında, python'un diskten okuması, her seferinde dosyayı derlemesi ve çalıştırması, ayrıca çalıştırma süresini yavaşlatan Andrew noktaları gibi yükleme modülleri gerekir . Python betiğinin bayt kodunu derlerseniz, kodu çalıştırmanın% 50 daha az zaman aldığını fark edeceksiniz:

python some.py > /dev/null  0.25s user 0.01s system 63% cpu 0.413 total

derlenmiş:

./some.pyc  0.22s user 0.00s system 77% cpu 0.282 total

Gördüğünüz gibi, farklı araçlar arasında zamanın uygulanmasını etkileyebilecek birkaç faktör var.


3

Diğer cevapları okuma avantajım oldu. Burada böyle büyük bir tamsayı ile konum uğraşan de o yüzden benim gibi başlayanlar insanlar nedenini bilmeli için Pythonve bcbunu sağ çağrışımlı bu olmadığını, üslü genişlemesini hangi vasıta 6^36biz değerlendirirken ziyade 6^46656oldukça büyük olan. 1

Aşağıdaki komutlardaki varyasyonları kullanarak, hem timeayrılmış sözcüğün hem de komutun çıktısının belirli bir elemanı için bir ortalama çıkarabiliriz :

for i in {1..1000}; do (time echo 6^6^6 | bc > /dev/null) 2>&1; done | grep 'rea' | sed -e s/.*m// | awk '{sum += $1} END {print sum / NR}'

for i in {1..1000}; do (/usr/bin/time -v sh -c 'echo 6^6^6 | bc > /dev/null') 2>&1; done | grep 'Use' | sed -e s/.*:// | awk '{sum += $1} END {print sum / NR}'

Başka bir rotaya gidip dosyayı karşılaştırmadan tamamen kaldırmak mümkündür. Ayrıca, böyle bir şey ile BC'nin zamanlama karşılaştırabilirsiniz dcolarak, komuta tarihsel eski ikincisi için "ön uç işlemcisi" dir. Aşağıdaki komutlar zamanlandı:

echo 6^6^6 | bc
echo 6 6 6 ^ ^ p | dc
echo print 6**6**6 | python2.7

Not dckomut sola birleşim olduğu üs için. 2

time1000 yineleme için (bash) ile bazı sonuçlarımız var (saniye olarak):

0.229678 real bc
0.228348 user bc
0.000569 sys bc
0.23306  real dc
0.231786 user dc
0.000395 sys dc
0.07 real python
0.065907 user python
0.003141 sys python

bcve dcbu bağlamda karşılaştırılabilir performans sunar.

GNU komutundan daha az kesin 3 sonuç (ölçek hassasiyeti burada geçerli değil ancak sonuçlar benzer):/usr/bin/timetime

0.2224 user bc
0 sys bc
0.23 Elapsed bc
0.22998 user dc
0 sys dc
0.23 Elapsed dc
0.06008 user python
0 sys python
0.07 Elapsed python

Bir avantajı /usr/bin/timesunduğu olmasıdır -vsonunda yararlı olabilir çok daha fazla bilgi verir seçeneği.

Python modülüyle konuşmak için bunu dahili olarak değerlendirmek mümkündür timeit:

python2.7 -m timeit -n 1000 -r 1 'print 6**6**6' | grep 'loops'
1000 loops, best of 1: 55.4 msec per loop

Bu daha önce gördüğümüzden biraz daha hızlı. Tercümanın kendisini deneyelim:

>>> import timeit
>>> import sys
>>> import os
>>> T = timeit.Timer("print 6**6**6")
>>> n = int(1000)
>>> f = open(os.devnull, 'w')
>>> sys.stdout = f
>>> t = t.timeit(n)
>>> sys.stdout = sys.__stdout__
>>> print t/n
0.0553743481636

Bu gördüğüm en hızlı şey.


Bunun gibi daha küçük bir üssü değerlendiriyorsak 6^6, zaman komutu şaşırtıcı sonuçlar verir - forşu anda kullandığımız aynı döngü komutlarını kullanarak :

0.001001 bc real
0.000304 user
0.000554 sys
0.014    python real i.e. 10x more than bc??
0.010432 user
0.002606 sys

Yani daha küçük bir tamsayı bcile aniden çok daha hızlı ?? Sistemin yeniden başlatılmasından ikinci çalışmaya kadar hiçbir fark yoktur. Ancak aynı zamanda, timeitPython için kullanırsak , şunu elde ederiz:

python2.7 -m timeit -n 100000 -r 1 'print 6**6' | grep loops  
100000 loops, best of 1: 0.468 usec per loop

Bu mikrosaniye , milisaniye değil, bu yüzden fordöngü kullanan daha yavaş sonuçlarla uyuşmuyor . Belki bunu daha ileri düzeyde test etmek için başka araçlar gerekir ve diğerlerinin de açıkladığı gibi burada gözle görünenden daha fazlası var. Görünüşe göre Python soru senaryosunda daha hızlıydı, ancak sonuçların bunun ötesinde çizilip çizilemeyeceği belli değil ...


1. Echo'nun aritmetik genişlemesi gibi bir şeyin kapsamı dışında olduğunu söylemeye gerek yok, yani echo $((6**6**6))- bashbunun için de doğru bir ilişki olabilir 6^6^6 = 6^(6^6).

2. Bununla karşılaştırın: 6 6 ^ 6 ^ p.

3. GNU zaman komutunun BSD UNIX'te çalıştırıldığında daha fazla bilgi sağlaması mümkündür (GNU zaman bilgisi belgesi): 'Zaman' ile gösterilen çoğu bilgi 'wait3' sistem çağrısından türetilmiştir. Rakamlar sadece 'wait3' tarafından döndürülenler kadar iyidir. Birçok sistem, 'zamanın' raporlayabileceği tüm kaynakları ölçmez; bu kaynaklar sıfır olarak bildirilir. Kaynakların çoğunu veya tümünü ölçen sistemler, 4.2 veya 4.3BSD'ye dayanmaktadır. Daha sonra BSD sürümleri, daha az kaynak ölçen farklı bellek yönetim kodları kullanır. - Durum bilgisi döndüren 'wait3' çağrısı olmayan sistemlerde, bunun yerine 'times' sistem çağrısı kullanılır. 'Wait3' den çok daha az bilgi veriyor, bu yüzden bu sistemlerde 'zaman' kaynakların çoğunu sıfır olarak rapor ediyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.