Saya menjalankan loop ini untuk memeriksa dan mencetak beberapa hal setiap detik. Namun, karena perhitungan mungkin memerlukan beberapa ratus milidetik, waktu yang dicetak terkadang melompati satu detik.
Apakah ada cara untuk menulis perulangan sehingga saya dijamin akan mendapatkan hasil cetak setiap detik? (Asalkan, tentu saja, bahwa perhitungan dalam loop memakan waktu kurang dari satu detik :))
while true; do
TIME=$(date +%H:%M:%S)
# some calculations which take a few hundred milliseconds
FOO=...
BAR=...
printf '%s %s %s\n' $TIME $FOO $BAR
sleep 1
done
bash
timestamps
sleep
sebagainya
sumber
sumber
sched(7)
API (POSIX: lihat<sched.h>
dan halaman-halaman yang ditautkan dari sana), Anda pada dasarnya tidak dapat memiliki jaminan real-time dari formulir ini.Jawaban:
Untuk sedikit lebih dekat dengan kode asli, yang saya lakukan adalah:
Ini sedikit mengubah semantik: jika barang Anda membutuhkan waktu kurang dari satu detik, itu hanya akan menunggu detik penuh berlalu. Namun, jika barang Anda membutuhkan waktu lebih dari satu detik untuk alasan apa pun, itu tidak akan terus menelurkan lebih banyak lagi subproses tanpa pernah ada akhirnya.
Jadi barang Anda tidak pernah berjalan secara paralel, dan tidak di latar belakang, sehingga variabel berfungsi seperti yang diharapkan juga.
Perhatikan bahwa jika Anda memulai tugas latar belakang tambahan juga, Anda harus mengubah
wait
instruksi untuk hanya menunggusleep
proses secara khusus.Jika Anda membutuhkannya agar lebih akurat, Anda mungkin hanya perlu menyinkronkannya ke jam sistem dan tidur ms bukannya detik penuh.
Bagaimana cara menyinkronkan ke jam sistem? Tidak tahu benar, upaya bodoh:
Default:
Output: 003511461 010510925 016081282 021643477 028504349 03 ... (terus berkembang)
Disinkronkan:
Output: 002648691 001098397 002514348 001293023 001679137 00 ... (tetap sama)
sumber
sleep
menangani pecahan detik?sleep 0.9 || sleep 1
parameter yang tidak valid cukup satu-satunya alasan untuk tidur gagal.sleep 0.9
akan ditafsirkan sebagaisleep 0
implementasi naif (mengingat itulah yangatoi
akan dilakukan). Tidak yakin apakah itu benar-benar menghasilkan kesalahan.gdate
pada macOS untuk membuatdate +%N
pekerjaan.)Jika Anda dapat menyusun ulang loop Anda menjadi skrip / oneliner maka cara paling sederhana untuk melakukannya adalah dengan
watch
danprecise
opsinya.Anda dapat melihat efeknya dengan
watch -n 1 sleep 0.5
- ini akan menunjukkan hitungan detik, tetapi kadang-kadang akan melewatkan satu detik. Menjalankannyawatch -n 1 -p sleep 0.5
akan menghasilkan dua kali per detik, setiap detik, dan Anda tidak akan melihat ada lompatan.sumber
Menjalankan operasi dalam subkulit yang berjalan sebagai pekerjaan latar belakang akan membuat mereka tidak terlalu mengganggu
sleep
.Satu-satunya waktu "dicuri" dari satu detik adalah waktu yang dibutuhkan untuk meluncurkan subkulit, sehingga akhirnya akan melewatkan satu detik, tetapi mudah-mudahan lebih jarang daripada kode aslinya.
Jika kode dalam subkulit berakhir menggunakan lebih dari satu detik, loop akan mulai mengumpulkan pekerjaan latar belakang dan akhirnya kehabisan sumber daya.
sumber
Alternatif lain (jika Anda tidak dapat menggunakan, misalnya,
watch -p
seperti yang disarankan Maelstrom) adalahsleepenh
[ manpage ], yang dirancang untuk ini.Contoh:
Perhatikan
sleep 0.2
di sana simulasi melakukan tugas memakan waktu makan sekitar 200 ms. Meskipun demikian, output nanodetik tetap stabil (well, menurut standar OS non-realtime) - ini terjadi sekali per detik:Itu di bawah 1ms berbeda, dan tidak ada tren. Itu cukup bagus; Anda harus mengharapkan memantul setidaknya 10ms jika ada beban pada sistem - tetapi masih tidak ada penyimpangan dari waktu ke waktu. Yaitu, Anda tidak akan kehilangan satu detik.
sumber
Dengan
zsh
:Jika tidur Anda tidak mendukung detik titik mengambang, Anda dapat menggunakan
zsh
katazselect
ganti (setelah azmodload zsh/zselect
):Itu tidak boleh melayang selama perintah dalam loop membutuhkan waktu kurang dari satu detik untuk dijalankan.
sumber
Saya memiliki persyaratan yang sama persis untuk skrip shell POSIX, di mana semua pembantu (usleep, GNUsleep, sleepenh, ...) tidak tersedia.
lihat: https://stackoverflow.com/a/54494216
sumber