Seberapa akurat waktu python's time.sleep ()?


95

Saya bisa memberikannya angka floating point, seperti

time.sleep(0.5)

tapi seberapa akurat itu? Jika saya memberikannya

time.sleep(0.05)

apakah akan benar-benar tidur sekitar 50 ms?

Jawaban:


79

Keakuratan fungsi time.sleep tergantung pada akurasi tidur OS yang mendasarinya. Untuk OS non-realtime seperti Windows stok, interval terkecil yang dapat Anda gunakan untuk tidur adalah sekitar 10-13ms. Saya telah melihat tidur yang akurat dalam beberapa milidetik dari waktu itu ketika di atas minimum 10-13ms.

Pembaruan: Seperti yang disebutkan dalam dokumen yang dikutip di bawah ini, adalah umum untuk melakukan tidur dalam satu lingkaran yang akan memastikan untuk kembali tidur jika membangunkan Anda lebih awal.

Saya juga harus menyebutkan bahwa jika Anda menjalankan Ubuntu, Anda dapat mencoba kernel pseudo real-time (dengan set patch RT_PREEMPT) dengan menginstal paket kernel rt (setidaknya di Ubuntu 10.04 LTS).

EDIT: Koreksi kernel Linux non-realtime memiliki interval tidur minimum lebih dekat ke 1ms kemudian 10ms tetapi bervariasi dengan cara non-deterministik.


8
Sebenarnya, kernel Linux secara default memiliki tick rate yang lebih tinggi untuk beberapa saat, jadi sleep "minimum" lebih mendekati 1ms daripada 10ms. Ini tidak dijamin - aktivitas sistem lain dapat membuat kernel tidak dapat menjadwalkan proses Anda secepat yang Anda inginkan, bahkan tanpa pertentangan CPU. Menurut saya, itulah yang coba diperbaiki kernel waktu-nyata. Tetapi, kecuali jika Anda benar-benar membutuhkan perilaku realtime, cukup menggunakan tick rate tinggi (pengaturan kernel HZ) akan membuat Anda tidak dijamin-tetapi-resolusi tinggi tidur di Linux tanpa menggunakan sesuatu yang istimewa.
Glenn Maynard

1
Ya, Anda benar, saya mencoba dengan Linux 2.6.24-24 dan berhasil mendapatkan tingkat pembaruan yang mendekati 1000 Hz. Pada saat saya melakukan ini, saya juga menjalankan kode di Mac dan Windows, jadi saya mungkin bingung. Saya tahu windows XP setidaknya memiliki tick rate sekitar 10ms.
Joseph Lisee

Pada Windows 8 saya mendapatkan hanya di bawah 2ms
markmnl

2
Juga keakuratannya tidak hanya bergantung pada OS tetapi apa yang dilakukan OS pada Windows dan Linux jika mereka sibuk melakukan sesuatu yang lebih penting sleep()dari dokumen "waktu penangguhan mungkin lebih lama daripada yang diminta oleh jumlah yang sewenang-wenang karena penjadwalan aktivitas lain dalam sistem ".
markmnl

56

Orang-orang benar tentang perbedaan antara sistem operasi dan kernel, tetapi saya tidak melihat perincian di Ubuntu dan saya melihat perincian 1 ms di MS7. Menyarankan implementasi berbeda dari time.sleep, bukan hanya tick rate yang berbeda. Pemeriksaan lebih dekat menunjukkan granularitas 1μs di Ubuntu, tetapi itu karena fungsi time.time yang saya gunakan untuk mengukur akurasi. Linux dan perilaku time.sleep khas Windows dengan Python


6
Sangat menarik bagaimana Linux memilih untuk selalu tidur lebih lama dari yang diminta, sedangkan Microsoft telah memilih pendekatan yang berlawanan.
jleahy

2
@jleahy - pendekatan linux masuk akal bagi saya: sleep sebenarnya adalah pelepasan prioritas eksekusi untuk sejumlah waktu setelah itu Anda sekali lagi menyerahkan diri Anda pada kehendak penjadwal (yang mungkin atau mungkin tidak menjadwalkan Anda untuk eksekusi segera) .
underrun

2
bagaimana kamu mendapatkan hasilnya? Bisakah Anda memberikan kode sumber? Grafik tersebut tampak seperti artefak menggunakan pengatur waktu yang berbeda untuk mengukur waktu dan tidur (Pada prinsipnya, Anda bahkan dapat menggunakan penyimpangan di antara pengatur waktu sebagai sumber keacakan ).
jfs

2
@JF Sebastian - Fungsi yang saya gunakan ada di socsci.ru.nl/wilberth/computer/sleepAccuracy.html . Grafik ketiga di sana menunjukkan efek yang mirip dengan apa yang Anda lihat, tetapi hanya 1 ‰.
Wilbert

1
@JF Sebastian Saya menggunakan time.clock () di windows
Wilbert

26

Dari dokumentasi :

Di sisi lain, ketepatan time()dan sleep()lebih baik daripada padanan Unix: waktu dinyatakan sebagai bilangan floating point, time()mengembalikan waktu paling akurat yang tersedia (menggunakan Unix gettimeofday jika tersedia), dan sleep()akan menerima waktu dengan pecahan bukan nol (Unix selectdigunakan untuk menerapkan ini, jika tersedia).

Dan lebih khusus lagi wrt sleep():

Tangguhkan eksekusi selama beberapa detik. Argumennya mungkin berupa angka floating point untuk menunjukkan waktu tidur yang lebih tepat. Waktu penangguhan sebenarnya mungkin kurang dari yang diminta karena setiap sinyal yang tertangkap akan menghentikan sleep()pelaksanaan rutinitas penangkapan sinyal berikut. Selain itu, waktu penangguhan mungkin lebih lama dari yang diminta oleh jumlah yang sewenang-wenang karena penjadwalan aktivitas lain di sistem.


1
Adakah yang bisa menjelaskan "karena setiap sinyal yang tertangkap akan menghentikan tidur () setelah pelaksanaan rutinitas penangkapan sinyal itu"? Sinyal mana yang dimaksud? Terima kasih!
Diego Herranz

1
Sinyal ibarat notifikasi yang dikelola OS ( en.wikipedia.org/wiki/Unix_signal ), artinya jika OS menangkap sinyal, maka sleep () selesai setelah memperlakukan sinyal tersebut.
ArianJM

24

Berikut tindak lanjut saya untuk jawaban Wilbert: sama untuk Mac OS X Yosemite, karena belum banyak disebutkan.Perilaku tidur Mac OS X Yosemite

Sepertinya banyak waktu tidur sekitar 1,25 kali dari waktu yang Anda minta dan terkadang tidur antara 1 dan 1,25 kali waktu yang Anda minta. Hampir tidak pernah (~ dua kali dari 1000 sampel) tidur secara signifikan lebih dari 1,25 kali waktu yang Anda minta.

Juga (tidak ditampilkan secara eksplisit) hubungan 1,25 tampaknya bertahan cukup baik sampai Anda berada di bawah sekitar 0,2 ms, setelah itu mulai menjadi sedikit kabur. Selain itu, waktu sebenarnya tampaknya menetap sekitar 5 md lebih lama dari yang Anda minta setelah jumlah waktu yang diminta di atas 20 md.

Sekali lagi, ini tampaknya merupakan implementasi yang sama sekali berbeda sleep()di OS X daripada di Windows atau di mana pun Linux kernal yang digunakan Wilbert.


Bisakah Anda mengunggah kode sumber untuk tolok ukur ke github / bitbucket?
jfs

3
Saya sudah mencoba itu di mesin saya. Hasilnya mirip dengan jawaban @ Wilbert .
jfs

Saya kira tidur itu sendiri akurat tetapi penjadwalan Mac OS X tidak cukup akurat untuk menyediakan CPU cukup cepat sehingga bangun dari tidur tertunda. Jika waktu bangun yang akurat itu penting, tampaknya tidur harus diatur ke 0,75 kali dari yang diminta dan periksa waktu setelah bangun dan berulang kali tidur untuk waktu yang lebih sedikit hingga waktu yang tepat.
Mikko Rantalainen

16

Mengapa Anda tidak mencari tahu:

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

Sebagai catatan, saya mendapatkan sekitar 0.1ms kesalahan pada HTPC saya dan 2ms di laptop saya, keduanya mesin linux.


10
Pengujian empiris akan memberi Anda pandangan yang sangat sempit. Ada banyak kernel, sistem operasi, dan konfigurasi kernel yang mempengaruhi hal ini. Kernel Linux yang lebih lama secara default menggunakan tick rate yang lebih rendah, yang menghasilkan perincian yang lebih besar. Dalam implementasi Unix, sinyal eksternal selama mode tidur akan membatalkannya kapan saja, dan implementasi lain mungkin memiliki gangguan serupa.
Glenn Maynard

6
Tentu saja observasi empiris tidak bisa dialihkan. Selain sistem operasi dan kernel, ada banyak masalah sementara yang memengaruhi hal ini. Jika jaminan hard real time diperlukan, maka keseluruhan desain sistem dari perangkat keras hingga perlu dipertimbangkan. Saya baru saja menemukan hasil yang relevan mengingat pernyataan bahwa 10ms adalah akurasi minimum. Saya tidak betah di dunia Windows, tetapi sebagian besar distro linux telah menjalankan kernel tanpa tick untuk sementara waktu sekarang. Dengan multicore yang sekarang lazim, kemungkinan besar dijadwalkan sangat dekat dengan waktu tunggu.
Ants Aasma

4

Koreksi kecil, beberapa orang menyebutkan bahwa tidur bisa diakhiri lebih awal dengan sebuah sinyal. Dalam 3.6 dokumen dikatakan,

Diubah pada versi 3.5: Fungsi sekarang tidur setidaknya beberapa detik bahkan jika tidur itu diinterupsi oleh sinyal, kecuali jika penangan sinyal memunculkan pengecualian (lihat PEP 475 untuk alasannya).


3

Anda tidak dapat benar-benar menjamin apa pun tentang tidur (), kecuali bahwa setidaknya tidur akan berusaha sebaik mungkin selama Anda memberi tahu (sinyal dapat mematikan tidur Anda sebelum waktu habis, dan banyak lagi hal yang dapat membuatnya berjalan panjang).

Yang pasti, minimum yang bisa Anda peroleh pada sistem operasi desktop standar adalah sekitar 16 ms (perincian pengatur waktu ditambah waktu ke sakelar konteks), tetapi kemungkinan% deviasi dari argumen yang diberikan akan menjadi signifikan ketika Anda mencoba tidur selama 10 milidetik.

Sinyal, utas lain yang menahan GIL, kesenangan penjadwalan kernel, peningkatan kecepatan prosesor, dll. Semuanya dapat merusak dengan durasi utas / proses Anda benar-benar tidur.


3
Dokumentasi mengatakan sebaliknya:> Waktu penangguhan sebenarnya mungkin kurang dari yang diminta karena sinyal yang tertangkap akan menghentikan tidur () setelah eksekusi rutinitas penangkapan sinyal itu.
Glenn Maynard

Ah poin yang adil, perbaiki posnya, meskipun tidur lebih lama () jauh lebih mungkin daripada yang lebih pendek.
Nick Bastin

1
Dua setengah tahun kemudian ... dokumentasinya masih ada. Di Windows, sinyal tidak akan menghentikan tidur (). Diuji pada Python 3.2, WinXP SP3.
Dave

Ya, tetapi sinyal pre-empting sleep tidak biasa, misalnya KILL, dokumentasi juga mengatakan: "Selain itu, waktu penangguhan mungkin lebih lama daripada yang diminta oleh jumlah yang sewenang-wenang karena penjadwalan aktivitas lain dalam sistem." yang lebih khas.
markmnl

1
Singnals dan Windows itu konyol. Di Windows, waktu Python.sleep () menunggu di ConsoleEvent untuk merekam hal-hal seperti Ctrl-C.
schlenk

1

jika Anda membutuhkan waktu tidur yang lebih presisi atau lebih rendah, pertimbangkan untuk membuat sendiri:

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()

Jangan gunakan variabel untuk meneruskan argumen sleep (), Anda harus memasukkan kalkulasi langsung ke sleep ()


Dan kembalinya terminal saya

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)

Pada windows 7 / Python 3.8 dikembalikan 1000untuk saya, bahkan jika saya menyetel nilai sleep ke0.0005

jadi 1ms sempurna

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.