Python'un time.sleep () doğruluğu ne kadar?


95

Ona kayan nokta numaraları verebilirim, örneğin

time.sleep(0.5)

ama ne kadar doğru? Eğer verirsem

time.sleep(0.05)

gerçekten yaklaşık 50 ms uyuyacak mı?

Yanıtlar:


79

Time.sleep işlevinin doğruluğu, temelde yatan işletim sisteminizin uyku doğruluğuna bağlıdır. Stok Windows gibi gerçek zamanlı olmayan işletim sistemleri için uyuyabileceğiniz en küçük aralık yaklaşık 10-13 ms'dir. Minimum 10-13 ms'nin üzerindeyken birkaç milisaniye içinde doğru uykular gördüm.

Güncelleme: Aşağıda belirtilen belgelerde bahsedildiği gibi, sizi erken uyandırırsa tekrar uykuya dönmenizi sağlayacak bir döngüde uykuyu yapmak yaygındır.

Ayrıca Ubuntu kullanıyorsanız, rt çekirdek paketini (en azından Ubuntu 10.04 LTS'de) kurarak sözde gerçek zamanlı bir çekirdeği (RT_PREEMPT yama setiyle) deneyebileceğinizi de belirtmeliyim.

DÜZENLEME: Gerçek zamanlı olmayan Linux çekirdeklerinin düzeltilmesi, 1ms'den 10ms'ye çok daha yakın minimum uyku aralığına sahiptir, ancak deterministik olmayan bir şekilde değişir.


8
Aslında, Linux çekirdekleri uzun bir süredir varsayılan olarak daha yüksek bir tıklama oranına sahipler, bu nedenle "minimum" uyku 10ms'den 1ms'ye çok daha yakındır. Garanti edilmez - diğer sistem etkinlikleri, çekirdeğin CPU çekişmesi olmasa bile işleminizi istediğiniz anda planlamamasına neden olabilir. Gerçek zamanlı çekirdeklerin düzeltmeye çalıştığı şey bu, sanırım. Ancak, gerçek zamanlı davranışa gerçekten ihtiyacınız olmadıkça, yalnızca yüksek bir onay oranı (çekirdek HZ ayarı) kullanmak, Linux'ta özel bir şey kullanmadan size garanti edilmeyen ancak yüksek çözünürlüklü uykular sağlayacaktır.
Glenn Maynard

1
Evet haklısınız, Linux 2.6.24-24 ile denedim ve 1000 Hz güncelleme oranlarına oldukça yaklaşabildim. Bunu yaptığım sırada kodu Mac ve Windows'ta da çalıştırıyordum, bu yüzden muhtemelen kafam karıştı. Windows XP'nin en azından 10ms'lik bir tıklama oranına sahip olduğunu biliyorum.
Joseph Lisee

Windows 8'de
2ms'nin

2
Ayrıca, doğruluk sadece işletim sistemine değil, aynı zamanda işletim sisteminin hem Windows hem de Linux'ta ne yaptığına sleep(), belgelerden daha önemli bir şey yapmakla meşgullerse "askıya alma süresi, sistemdeki diğer etkinlik ".
markmnl

56

İnsanlar işletim sistemleri ve çekirdekler arasındaki farklar konusunda oldukça haklılar, ancak Ubuntu'da herhangi bir ayrıntı görmüyorum ve MS7'de 1 ms'lik bir ayrıntı görüyorum. Time.sleep'nin farklı bir uygulamasını önermek, yalnızca farklı bir tik hızı değil. Daha yakından inceleme, bu arada Ubuntu'da 1μs ayrıntı düzeyi önerir, ancak bu, doğruluğu ölçmek için kullandığım time.time işlevinden kaynaklanıyor. Python'da Linux ve Windows tipik time.sleep davranışı


6
Linux'un her zaman istenenden biraz daha uzun süre uyumayı seçmesi ilginçtir, oysa Microsoft tam tersi yaklaşımı seçmiştir.
jleahy

2
@jleahy - linux yaklaşımı bana mantıklı geliyor: uyku gerçekten de belirli bir süre için yürütme önceliğinin serbest bırakılmasıdır ve sonrasında kendinizi bir kez daha programlayıcının iradesine teslim edersiniz (bu sizi hemen yürütme için planlayabilir veya etmeyebilir) .
2013

2
sonuçları nasıl aldın? Kaynak kodunu sağlayabilir misiniz? Grafik, zamanı ve uykuyu ölçmek için farklı zamanlayıcılar kullanmanın bir artefaktına benziyor (Prensipte, zamanlayıcılar arasındaki kaymayı bir rastgelelik kaynağı olarak bile kullanabilirsiniz ).
jfs

2
@JF Sebastian - Kullandığım işlev socsci.ru.nl/wilberth/computer/sleepAccuracy.html . Oradaki üçüncü grafik, gördüğünüze benzer, ancak yalnızca 1 ‰ olan bir etki gösterir.
Wilbert

1
@JF Sebastian Windows'ta time.clock () kullanıyorum
Wilbert

26

Gönderen belgeler :

Öte yandan, hassas time()ve sleep()Unix eşdeğer daha iyidir: kez kayan nokta sayısı olarak ifade edilir time(), en doğru zaman döner (Unix kullanılarak gettimeofday temin edilebilir), ve sleep()UNIX (sıfır olmayan bir fraksiyonu ile bir saat kabul selectkullanılan mümkün olan yerlerde bunu uygulamak için).

Ve daha spesifik wrt sleep():

Verilen saniye sayısı boyunca yürütmeyi askıya alın. Argüman, daha kesin bir uyku süresini belirtmek için bir kayan nokta numarası olabilir. Gerçek askıya alma süresi talep edilenden daha az olabilir çünkü yakalanan herhangi bir sinyal sleep(), o sinyalin yakalama rutininin müteakip yürütülmesini sona erdirecektir . Ayrıca, sistemdeki diğer aktivitelerin programlanması nedeniyle askıya alma süresi keyfi bir miktar tarafından talep edilenden daha uzun olabilir .


1
Herhangi biri "yakalanan herhangi bir sinyal, o sinyalin yakalama rutininin yürütülmesinin ardından uykuyu () sonlandıracağı için" açıklayabilir mi? Hangi sinyallere atıfta bulunuyor? Teşekkürler!
Diego Herranz

1
Sinyaller, işletim sisteminin yönettiği bildirimler gibidir ( en.wikipedia.org/wiki/Unix_signal ), bu, işletim sistemi bir sinyal yakalarsa, bu sinyali tedavi ettikten sonra uyku () işleminin bittiği anlamına gelir.
ArianJM

25

İşte Wilbert'in cevabının devamı: Mac OS X Yosemite için de aynısı, çünkü henüz pek bahsedilmedi.Mac OS X Yosemite'in uyku davranışı

Çoğu zaman talep ettiğiniz sürenin 1.25 katı kadar uyuyor ve bazen de talep ettiğiniz sürenin 1 ile 1.25 katı arasında uyuyor. Neredeyse hiçbir zaman (1000 numunenin ~ iki katı), talep ettiğiniz sürenin 1,25 katından önemli ölçüde daha fazla uyumaz.

Ayrıca (açıkça gösterilmemiştir) 1.25 ilişkisi, yaklaşık 0.2 ms'nin altına inene kadar oldukça iyi durumda görünüyor, ardından biraz bulanıklaşmaya başlıyor. Ek olarak, istenen süre 20 ms'nin üzerine çıktıktan sonra gerçek süre, isteğinizden yaklaşık 5 ms daha uzun sürecek gibi görünüyor.

Yine, sleep()OS X'te Windows veya hangi Linux kernal Wilbert'in kullandığı uygulamadan tamamen farklı bir uygulama gibi görünüyor .


Karşılaştırma için kaynak kodunu github / bitbucket'a yükleyebilir misiniz?
jfs

3
Ben denedim bunu benim makinede. Sonuç @ Wilbert'in cevabına benzer .
jfs

Uykunun kendisinin doğru olduğunu tahmin ediyorum, ancak Mac OS X zamanlaması, uykudan uyanmanın gecikmesi için CPU'yu yeterince hızlı sağlayacak kadar doğru değil. Doğru uyanma zamanı önemliyse, uykunun gerçekte talep edilenin 0,75 katına ayarlanması ve uyandıktan sonraki zamanı kontrol etmesi ve doğru saate kadar daha az ve daha az zamanda tekrar tekrar uyuması gerektiği görülmektedir.
Mikko Rantalainen

16

Neden öğrenmiyorsun:

from datetime import datetime
import time

def check_sleep(amount):
    start = datetime.now()
    time.sleep(amount)
    end = datetime.now()
    delta = end-start
    return delta.seconds + delta.microseconds/1000000.

error = sum(abs(check_sleep(0.050)-0.050) for i in xrange(100))*10
print "Average error is %0.2fms" % error

Kayıt için, her iki linux makinesinde HTPC'imde 0.1ms ve dizüstü bilgisayarımda 2ms hata alıyorum.


10
Ampirik testler size çok dar bir bakış açısı sağlayacaktır. Bunu etkileyen birçok çekirdek, işletim sistemi ve çekirdek yapılandırması vardır. Daha eski Linux çekirdekleri varsayılan olarak daha düşük bir işlem oranına sahiptir ve bu da daha büyük bir ayrıntı düzeyine neden olur. Unix uygulamasında, uyku sırasında harici bir sinyal herhangi bir zamanda onu iptal eder ve diğer uygulamalarda da benzer kesintiler olabilir.
Glenn Maynard

6
Tabii ki deneysel gözlem aktarılamaz. İşletim sistemleri ve çekirdekler dışında, bunu etkileyen birçok geçici sorun var. Zor gerçek zamanlı garantiler gerekiyorsa, donanımdan başlayarak tüm sistem tasarımının dikkate alınması gerekir. 10ms'nin minimum doğruluk olduğunu düşündüğümde sonuçları alakalı buldum. Windows dünyasında evde değilim, ancak çoğu Linux dağıtımı bir süredir kayıtsız çekirdekler çalıştırıyor. Çok çekirdekli artık yaygın olduğu için, zaman aşımına gerçekten yakın bir zamanda planlanması oldukça muhtemeldir.
Karıncalar Aasma

4

Küçük bir düzeltme, birkaç kişi uykunun bir sinyalle erken bitirilebileceğini söylüyor. In 3.6 docs diyor,

Sürüm 3.5'te değiştirildi: Sinyal işleyicinin bir istisna oluşturması dışında, uyku bir sinyalle kesilse bile işlev artık en az saniye uyur ( gerekçe için PEP 475'e bakın ).


3

Uyku () hakkında hiçbir şey garanti edemezsiniz, ancak en azından siz söylediğiniz sürece uyumak için en iyi çabayı gösterecektir (sinyaller uykunuzu zaman dolmadan öldürebilir ve daha birçok şey onu çalıştırabilir. uzun).

Elbette standart bir masaüstü işletim sisteminde elde edebileceğiniz minimum miktar 16 ms civarında olacaktır (zamanlayıcı ayrıntı düzeyi artı bağlam değiştirme süresi), ancak, siz denediğinizde sağlanan bağımsız değişkenden% sapma büyük olasılıkla önemli olacaktır. 10s milisaniye uyumak.

Sinyaller, GIL'i tutan diğer iş parçacıkları, çekirdek zamanlama eğlencesi, işlemci hızı adımlaması vb., İş parçacığınızın / işleminizin gerçekte uykuda olduğu süre boyunca hasara neden olabilir.


3
Belgeler aksini söylüyor:> Gerçek askıya alma süresi talep edilenden daha az olabilir çünkü yakalanan herhangi bir sinyal, o sinyalin yakalama rutininin yürütülmesinin ardından uykuyu () sonlandıracaktır.
Glenn Maynard

Ah adil nokta, gönderi düzeltildi, ancak daha uzun uyuma () daha kısa olanlardan çok daha olası.
Nick Bastin

1
İki buçuk yıl sonra ... belgeler hala yalan söylüyor. Windows'ta sinyaller uykuyu () sonlandırmaz. Python 3.2, WinXP SP3 üzerinde test edilmiştir.
Dave

Evet, ancak önceden uykudan uyanma sinyalleri olağandışıdır, örneğin KILL, dokümantasyon ayrıca şunları da söylüyor: "Ayrıca, sistemdeki diğer aktivitelerin programlanması nedeniyle askıya alma süresi keyfi bir miktar tarafından talep edilenden daha uzun olabilir." bu daha tipiktir.
markmnl

1
Singnals ve Windows çok saçma. Windows'ta Python time.sleep (), Ctrl-C gibi şeyleri yakalamak için bir ConsoleEvent'te bekler.
schlenk

1

Daha fazla hassasiyete veya daha kısa uyku sürelerine ihtiyacınız varsa, kendinizinkini yapmayı düşünün:

import time

def sleep(duration, get_now=time.perf_counter):
    now = get_now()
    end = now + duration
    while now < end:
        now = get_now()


0
def start(self):
    sec_arg = 10.0
    cptr = 0
    time_start = time.time()
    time_init = time.time()
    while True:
        cptr += 1
        time_start = time.time()
        time.sleep(((time_init + (sec_arg * cptr)) - time_start ))

        # AND YOUR CODE .......
        t00 = threading.Thread(name='thread_request', target=self.send_request, args=([]))
        t00.start()

Sleep () argümanını iletmek için bir değişken kullanmayın, hesaplamayı doğrudan sleep'e () eklemelisiniz.


Ve terminalimin dönüşü

1 ───── 17:20: 16.891 ───────────────────

2 ───── 17: 20: 18,891 ───────────────────

3 ───── 17:20: 20.891 ───────────────────

4 ───── 17: 20: 22,891 ───────────────────

5 ───── 17:20: 24.891 ───────────────────

....

689 ─── 17: 43: 12.891 ────────────────────

690 ─── 17: 43: 14.890 ────────────────────

691 ─── 17: 43: 16.891 ────────────────────

692 ─── 17: 43: 18,890 ────────────────────

693 ─── 17: 43: 20.891 ────────────────────

...

727 ─── 17: 44: 28.891 ────────────────────

728 ─── 17: 44: 30.891 ────────────────────

729 ─── 17: 44: 32.891 ────────────────────

730 ─── 17: 44: 34,890 ────────────────────

731 ─── 17: 44: 36.891 ────────────────────


0
def test():
    then = time.time()  # get time at the moment
    x = 0
    while time.time() <= then+1:  # stop looping after 1 second
        x += 1
        time.sleep(0.001)  # sleep for 1 ms
    print(x)

Windows 7 / Python 3.8'de 1000, uyku değerini şu şekilde ayarlasam bile benim için geri döndü0.0005

yani mükemmel bir 1 ms

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.