Saya ingin berulang kali menjalankan fungsi dalam Python setiap 60 detik selamanya (seperti NSTimer di Objective C). Kode ini akan berjalan sebagai daemon dan secara efektif seperti memanggil skrip python setiap menit menggunakan cron, tetapi tanpa mengharuskannya diatur oleh pengguna.
Dalam pertanyaan ini tentang cron diimplementasikan dalam Python , solusinya tampaknya secara efektif hanya tidur () selama x detik. Saya tidak membutuhkan fungsi canggih seperti itu jadi mungkin sesuatu seperti ini akan berfungsi
while True:
# Code executed here
time.sleep(60)
Apakah ada masalah yang dapat diperkirakan dengan kode ini?
time.sleep(60)
dapat kembali lebih awal dan kemudianJawaban:
Jika program Anda belum memiliki loop acara, gunakan modul sched , yang mengimplementasikan penjadwal acara tujuan umum.
Jika Anda telah menggunakan perpustakaan event loop seperti
asyncio
,trio
,tkinter
,PyQt5
,gobject
,kivy
, dan banyak lainnya - hanya jadwal tugas menggunakan metode loop acara yang ada perpustakaan, sebagai gantinya.sumber
enterabs()
untuk menghindarinya. Berikut ini adalah versi non-drifting untuk perbandingan .time.sleep
dapat menumpuk di sini. "jalankan setiap X detik" dan "jalankan dengan penundaan ~ X detik berulang kali" tidak sama. Lihat juga komentar iniKunci putaran waktu Anda ke jam sistem seperti ini:
sumber
twisted
jawabannya adalah satu-satunya jawaban yang menjalankan fungsi setiapx
detik. Sisanya menjalankan fungsi dengan penundaan selamax
detik setelah setiap panggilan.from time import time, sleep
karena implikasi eksistensial;)starttime
jika Anda mulai dengan menyinkronkannya ke waktu tertentu:time.sleep(60 - time.time() % 60)
telah bekerja dengan baik untuk saya. Saya telah menggunakannyatime.sleep(1200 - time.time() % 1200)
dan memberi saya log di:00 :20 :40
, persis seperti yang saya inginkan.sleep()
,timer()
presisi dan berapa lama waktu yang dibutuhkan untuk mengeksekusi tubuh loop tetapi pada iterasi rata-rata selalu terjadi pada batas-batas selang (bahkan jika beberapa dilewati):while keep_doing_it(): sleep(interval - timer() % interval)
. Bandingkan dengan diwhile keep_doing_it(): sleep(interval)
mana kesalahan dapat terakumulasi setelah beberapa iterasi.Anda mungkin ingin mempertimbangkan Twisted yang merupakan pustaka jaringan Python yang mengimplementasikan Pola Reactor .
Sementara "while True: sleep (60)" mungkin akan berfungsi Twisted mungkin sudah mengimplementasikan banyak fitur yang pada akhirnya Anda perlukan (daemonisasi, logging atau penanganan pengecualian seperti yang ditunjukkan oleh bobince) dan mungkin akan menjadi solusi yang lebih kuat
sumber
Jika Anda ingin cara non-pemblokiran untuk menjalankan fungsi Anda secara berkala, alih-alih pemblokiran tak terbatas saya akan menggunakan timer berulir. Dengan cara ini kode Anda dapat terus berjalan dan melakukan tugas-tugas lain dan masih memiliki fungsi Anda dipanggil setiap n detik. Saya menggunakan teknik ini banyak untuk mencetak info kemajuan pada tugas-tugas panjang, CPU / Disk / Jaringan.
Berikut kode yang saya posting dalam pertanyaan yang sama, dengan kontrol start () dan stop ():
Pemakaian:
Fitur:
start()
danstop()
aman untuk dipanggil beberapa kali bahkan jika timer sudah mulai / berhentiinterval
kapan saja, itu akan efektif setelah dijalankan berikutnya. Sama untukargs
,kwargs
dan bahkanfunction
!sumber
def _run(self)
saya mencoba membungkus kepala saya di sekitar mengapa Anda meneleponself.start()
sebelumnyaself.function()
. Bisakah Anda menguraikan? Saya akan berpikir dengan meneleponstart()
duluself.is_running
akan selaluFalse
demikian maka kami akan selalu memutar utas baru.x
detik (yaitu t = 0, t = 1x, t = 2x, t = 3x, ...) di mana pada poster asli kode sampel menjalankan fungsi dengan interval x detik di antaranya. Juga, solusi ini saya percaya memiliki bug jikainterval
lebih pendek dari waktu yang dibutuhkanfunction
untuk mengeksekusi. Dalam hal ini,self._timer
akan ditimpa dalamstart
fungsi..function()
setelah.start()
adalah menjalankan fungsi pada t = 0. Dan saya tidak berpikir itu akan menjadi masalah jikafunction
membutuhkan waktu lebih lama dari ituinterval
, tapi ya mungkin ada beberapa kondisi balap pada kode.Cara mudah yang saya yakini:
Dengan cara ini kode Anda dieksekusi, maka ia menunggu 60 detik kemudian dieksekusi lagi, menunggu, mengeksekusi, dll ... Tidak perlu menyulitkan hal-hal: D
sumber
time.sleep()
menjalankan sesuatu setiap X detiktime.sleep()
dalamwhile True
lingkaran seperti:def executeSomething(): print('10 sec left') ; while True: executeSomething(); time.sleep(10)
Jika Anda ingin melakukan ini tanpa memblokir kode yang tersisa, Anda dapat menggunakan ini untuk menjalankannya di utasnya sendiri:
Solusi ini menggabungkan beberapa fitur yang jarang ditemukan digabungkan dalam solusi lain:
threading.Timer
atau apa pun), ini akan mengakhiri rantai. Tidak ada eksekusi lebih lanjut akan terjadi kemudian, bahkan jika alasan masalah sudah diperbaiki. Lingkaran sederhana dan menunggu dengan sederhanasleep()
jauh lebih kuat dibandingkan.next_time += delay
sebagai gantinya.sumber
Berikut ini adalah pembaruan kode dari MestreLion yang menghindari drifiting dari waktu ke waktu.
Kelas RepeatTimer di sini memanggil fungsi yang diberikan setiap "interval" detik seperti yang diminta oleh OP; jadwal tidak tergantung pada berapa lama fungsi tersebut dijalankan. Saya suka solusi ini karena tidak memiliki dependensi perpustakaan eksternal; ini hanya python murni.
Penggunaan sampel (disalin dari jawaban MestreLion):
sumber
Saya menghadapi masalah yang sama beberapa waktu lalu. Mungkin http://cronus.readthedocs.org dapat membantu?
Untuk v0.2, cuplikan berikut berfungsi
sumber
Perbedaan utama antara itu dan cron adalah bahwa pengecualian akan membunuh daemon untuk selamanya. Anda mungkin ingin membungkusnya dengan catcher catcher dan logger.
sumber
Satu jawaban yang mungkin:
sumber
Saya akhirnya menggunakan modul jadwal . APInya bagus.
sumber
Saya menggunakan metode Tkinter after (), yang tidak "mencuri permainan" (seperti modul sched yang disajikan sebelumnya), yaitu memungkinkan hal-hal lain berjalan secara paralel:
do_something1()
dando_something2()
dapat berjalan secara paralel dan dalam kecepatan interval apa pun. Di sini, yang ke-2 akan dieksekusi dua kali lebih cepat. Perhatikan juga bahwa saya telah menggunakan penghitung sederhana sebagai syarat untuk mengakhiri salah satu fungsi. Anda dapat menggunakan contition apa pun yang Anda suka atau tidak ada jika Anda menjalankan fungsi apa saja sampai program berakhir (misalnya jam).sumber
after
jangan biarkan hal-hal berjalan paralel. Tkinter adalah single-threaded dan hanya dapat melakukan satu hal pada satu waktu. Jika sesuatu yang dijadwalkanafter
berjalan, itu tidak berjalan secara paralel dengan sisa kode. Jika keduanyado_something1
dando_something2
dijadwalkan untuk berjalan pada saat yang sama, mereka akan berjalan secara berurutan, bukan secara paralel.sched
solusi dan itu akan bekerja sama persis dengan Anda.Berikut adalah versi yang disesuaikan dengan kode dari MestreLion. Selain fungsi asli, kode ini:
1) tambahkan first_interval yang digunakan untuk memecat timer pada waktu tertentu (penelepon perlu menghitung first_interval dan meneruskannya)
2) menyelesaikan kondisi lomba dalam kode asli. Dalam kode asli, jika utas kontrol gagal membatalkan timer yang berjalan ("Hentikan timer, dan batalkan eksekusi tindakan timer. Ini hanya akan berfungsi jika timer masih dalam tahap menunggu." Dikutip dari https: // docs.python.org/2/library/threading.html ), timer akan berjalan tanpa henti.
sumber
Ini tampaknya jauh lebih sederhana daripada solusi yang diterima - apakah ada kekurangan yang tidak saya pertimbangkan? Datang ke sini mencari beberapa copy pasta mati-sederhana dan kecewa.
Yang tidak sinkron.
Memang ada pergeseran dalam arti bahwa jika tugas yang sedang berjalan membutuhkan waktu yang cukup lama, maka intervalnya menjadi 2 detik + waktu tugas, jadi jika Anda perlu penjadwalan yang tepat maka ini bukan untuk Anda.
Perhatikan
daemon=True
benderanya berarti utas ini tidak akan memblokir aplikasi untuk dimatikan. Sebagai contoh, ada masalah di manapytest
akan menggantung tanpa batas setelah menjalankan tes menunggu untuk ini berhenti.sumber
Saya menggunakan ini untuk menyebabkan 60 peristiwa per jam dengan sebagian besar peristiwa terjadi pada jumlah detik yang sama setelah satu menit:
Tergantung pada kondisi aktual Anda mungkin mendapatkan kutu panjang:
tetapi pada akhir 60 menit Anda akan memiliki 60 ticks; dan kebanyakan dari mereka akan terjadi pada offset yang benar ke menit yang Anda inginkan.
Pada sistem saya, saya mendapatkan penyimpangan khas <1/20 detik hingga kebutuhan untuk koreksi muncul.
Keuntungan dari metode ini adalah resolusi clock drift; yang dapat menyebabkan masalah jika Anda melakukan hal-hal seperti menambahkan satu item per centang dan Anda mengharapkan 60 item ditambahkan per jam. Kegagalan untuk memperhitungkan penyimpangan dapat menyebabkan indikasi sekunder seperti rata-rata bergerak untuk mempertimbangkan data terlalu jauh ke masa lalu yang mengakibatkan output yang salah.
sumber
misalnya, Tampilkan waktu setempat saat ini
sumber
sumber
Ini adalah solusi lain tanpa menggunakan perpustakaan tambahan.
sumber