Pertanyaan
Saya ingin dapat menjalankan perintah UNIX tepat setiap detik selama periode waktu yang lama .
Saya membutuhkan solusi, yang tidak ketinggalan setelah waktu tertentu, karena waktu itu perintah itu sendiri perlu untuk dieksekusi. tidur , menonton , dan skrip python tertentu semua gagal saya dalam hal ini.
Pada mikrokontroler seperti http://Arduino.cc saya akan melakukan itu melalui interupsi jam hardware. Saya ingin tahu apakah ada solusi shell script tepat waktu yang serupa. Semua solusi yang saya temukan di dalam StackExchange.com, menghasilkan jeda waktu yang nyata, jika melebihi jam. Lihat detail di bawah.
Tujuan / aplikasi praktis
Saya ingin menguji apakah koneksi jaringan saya terus naik dengan mengirimkan cap waktu via nc
(netcat) setiap 1 detik.
Pengirim:
precise-timestamp-generator | tee netcat-sender.txt | nc $receiver $port
Penerima:
nc -l -p $port > netcat-receiver.txt
Setelah selesai, bandingkan kedua log:
diff netcat-sender.txt netcat-receiver.txt
Difs akan menjadi cap waktu yang tidak dikirim. Dari sini saya akan tahu pada waktu apa LAN / WAN / ISP saya membuat masalah.
Solusi TIDUR
while [ true ]; do date "+%Y-%m-%d %H:%M:%S" ; sleep 1; done | tee timelog-sleep.txt
Mendapat offset tertentu dari waktu ke waktu, karena perintah dalam loop juga membutuhkan sedikit waktu.
Presisi
cat timelog-sleep.txt
2012-07-16 00:45:16
[...]
2012-07-16 10:20:36
Detik berlalu: 34520
wc -l timelog-sleep.txt
Baris dalam file: 34243
Presisi diringkas:
- 34520-34243 = 277 masalah pengaturan waktu
- 34520/34243 = 1,008 = diskon 0,8%
Solusi REPEAT PYTHON
Ditemukan di: Ulangi perintah Unix setiap x detik selamanya
repeat.py 1 "date '+%Y-%m-%d %H:%M:%S'" >> timelog-repeat-py.txt
Seharusnya menghindari waktu offset, tetapi gagal melakukannya.
Presisi
wc -l timelog-repeat-py.txt
2012-07-16 13:42:44
[...]
2012-07-16 16:45:24
Detik berlalu: 10960
wc -l timelog-repeat-py.txt
Baris dalam file: 10859
Presisi diringkas:
- 10960-10859 = 101 masalah waktu
- 10960/10859 = 1,009 = Diskon 0,9%
JAM TANGAN
watch -n 1 "date '+%Y-%m-%d %H:%M:%S' >> ~/Desktop/timelog-watch.txt"
Presisi
wc -l timelog-watch.txt
2012-07-16 11:04:08
[...]
2012-07-16 13:25:47
Detik berlalu: 8499
wc -l timelog-watch.txt
Baris dalam file: 8366
Presisi diringkas:
- 8499-8366 = 133 masalah pengaturan waktu.
- 8499/8366 = 1,016 = diskon 1,6%.
nice
proses yang tidur?Jawaban:
Bagaimana script Perl ini saya baru saja bekerja?
Menggunakan:
perl timer.pl 1 date '+%Y-%m-%d %H:%M:%S'
Ini telah berjalan 45 menit tanpa satu pun lompatan, dan saya menduga akan terus melakukannya kecuali a) beban sistem menjadi sangat tinggi sehingga fork () membutuhkan lebih dari satu detik atau b) lompatan kedua dimasukkan.
Tidak dapat menjamin, bagaimanapun, bahwa perintah berjalan pada interval kedua tepat, karena ada beberapa overhead, tetapi saya ragu itu jauh lebih buruk daripada solusi berbasis interrupt.
Saya menjalankannya sekitar satu jam dengan
date +%N
(nanodetik, ekstensi GNU) dan menjalankan beberapa statistik di atasnya. Kelambatan paling banyak adalah 1.155 mikrodetik. Rata-rata (rata-rata aritmatika) 216 µs, median 219 µs, standar deviasi 42 µs. Ini berjalan lebih cepat dari 270 95s 95% dari waktu. Saya tidak berpikir Anda bisa mengalahkannya kecuali dengan program C.sumber
GNU date
dengan+%N
dan setelah hanya 3 menit ia melemparkan kesalahan itu:Time::HiRes::sleep(-0.00615549): negative time not invented yet at ~/bin/repeat.pl line 23.
Baris 23 dalam skrip yang saya simpan:sleep $start - time();
Fungsi POSIX
ualarm()
memungkinkan Anda menjadwalkan kernel untuk memberi sinyal secara berkala pada proses Anda, dengan presisi mikrodetik.Menyiapkan program sederhana:
Menyusun
Kemudian tempelkan pada apa pun yang perlu Anda lakukan secara berkala seperti:
sumber
-std=c99
, Anda tidak akan mendapatkan peringatan tentang pengembalian yang hilang. Kalau tidak, Anda tidak perlu sesuatu yang istimewa. Apakah Anda salah mengetik nol ekstra?strace ./tick
akan menunjukkan kepada Anda apa yang dilakukannya dari perspektif syscallSudahkah Anda mencoba
watch
parameternya--precise
?Dari halaman manual:
Parameternya mungkin tidak tersedia di sistem Anda.
Anda juga harus mempertimbangkan apa yang harus terjadi ketika pelaksanaan program Anda membutuhkan lebih dari satu detik. Haruskah eksekusi yang dijadwalkan berikutnya dilewati, atau harus terlambat?
Pembaruan : Saya menjalankan skrip untuk beberapa waktu, dan tidak kehilangan satu langkah pun:
Memperbarui: The
--precise
bendera adalah tambahan Debian, patch Namun agak sederhana: http://patch-tracker.debian.org/patch/series/view/procps/1:3.2.8-9squeeze1/watch_precision_time.patchsumber
watch
mendukung opsi itu? Itu tidak ada pada mesin yang saya periksa.--precise
. Ini adalah tambahan Debian (3.2.8-9, watch_precision_time.patch)2012-07-24 07:20:21.864818595 2012-07-24 07:20:22.467458430 2012-07-24 07:20:23.068575669 2012-07-24 07:20:23.968415439
Hal-hal waktu nyata (kernel dll) ada di luar sana karena suatu alasan!crontab
memiliki resolusi 1 menit. Jika Anda baik-baik saja dengan akumulasi waktu jeda per menit itu dan kemudian mengatur ulang pada menit berikutnya, ide dasar ini bisa bekerja:Perhatikan bahwa
script.sh
ini juga dijalankan di latar belakang. Ini akan membantu meminimalkan kelambatan yang terakumulasi dengan setiap iterasi dari loop.Bergantung pada berapa banyak lag yang
sleep
dihasilkan, ada kemungkinan 59 detik tumpang tindih dengan 0 kedua pada menit berikutnya.EDIT untuk melemparkan beberapa hasil, dalam format yang sama seperti pada pertanyaan:
1 jam 52 menit = 6720 detik
0 masalah waktu, diskon 0%. Setiap akumulasi waktu disetel ulang setiap menit.
sumber
cron
tepat untuk yang kedua, tetapi tidak demikian halnya secara umum.Masalah Anda adalah bahwa Anda tidur dalam jumlah waktu yang tetap setelah Anda menjalankan program Anda tanpa mempertimbangkan jumlah waktu yang telah berlalu sejak terakhir kali Anda tidur.
Anda dapat melakukannya dengan bash atau bahasa pemrograman lainnya, tetapi kuncinya adalah menggunakan jam untuk menentukan berapa lama untuk menjadwalkan tidur berikutnya. Sebelum Anda tidur, periksa jam, lihat berapa banyak waktu yang tersisa, dan tidur perbedaannya.
Karena kompromi penjadwalan proses, Anda tidak dijamin untuk bangun tepat pada centang jam, tetapi Anda harus cukup dekat (dalam beberapa ms dibongkar, atau dalam beberapa ratus ms dalam pemuatan). Dan Anda tidak akan menumpuk kesalahan dari waktu ke waktu karena setiap kali Anda menyinkronkan ulang pada setiap siklus tidur dan menghapus setiap kesalahan yang terakumulasi.
Jika Anda perlu menekan tanda centang jam tepat, maka apa yang Anda cari adalah sistem operasi waktu nyata , yang dirancang persis untuk tujuan ini.
sumber
date +%S.%N
untuk mendapatkan jumlah detik dengan ketepatan sub-detik, danusleep
untuk tidur dengan ketepatan sub-detik, tetapi setelah itu hanya soal matematika.Saya selalu menyerah untuk menjalankan sesuatu tepat pada interval. Saya pikir Anda harus menulis program C, dan memperhatikan dengan sangat hati-hati untuk tidak melebihi porsi interval 1 detik dengan kode Anda sendiri. Anda mungkin harus menggunakan proses threading atau multipel, antar-komunikasi untuk membuatnya bekerja. Berhati-hatilah untuk menghindari overhead yang memulai thread atau memulai proses.
Salah satu referensi yang tampaknya tanggal relevan dengan 1993: Sebuah Acak Sampling Jam untuk Estimasi CPU Pemanfaatan dan Kode Profiling Anda akan ingin lihat lampiran "Musuh Source Code" untuk melihat bagaimana mereka diukur secara akurat interval waktu, dan "bangun" program mereka pada waktu yang tepat. Karena kode ini berumur 19 tahun, mungkin kode itu tidak akan port langsung atau mudah, tetapi jika Anda membacanya dan mencoba memahaminya, prinsip-prinsip yang terlibat mungkin memandu kode Anda.
EDIT: Menemukan referensi lain yang mungkin membantu: Efek Resolusi Jam pada Penjadwalan Proses Interaktif dan Soft Real-Time Yang seharusnya membantu Anda dengan latar belakang teoritis.
sumber
Lihatlah nanosleep () (dari http://linux.about.com/library/cmd/blcmdl2_nanosleep.htm ). Alih-alih membuat program Anda tidur 1 detik, buatlah tidur (1 - jumlah yang diperlukan untuk menjalankan) detik. Anda akan mendapatkan resolusi yang jauh lebih baik.
sumber
sleep
, yaitusleep 0.99
. Masalahnya adalah bahwa jumlah waktu yang diperlukan untuk menjalankan jauh dari konstan, bahkan nilai rata-rata dapat berfluktuasi dari waktu ke waktu.Coba jalankan perintah Anda di latar belakang sehingga tidak terlalu mempengaruhi timing loop, tetapi bahkan itu tidak akan cukup jika Anda tidak ingin ada akumulasi untuk jangka waktu yang lama karena pasti ada beberapa milidetik biaya yang terkait dengannya.
Jadi, ini sepertinya lebih baik, tetapi juga kemungkinan masih belum cukup baik:
Di komputer saya ini memberikan 2 kesalahan dalam 20 menit atau 0,1 per menit, yang merupakan peningkatan lima kali lipat lebih rendah selama Anda menjalankan.
sumber
sleep 1
adalah dijamin tidur setidaknya satu detik - tidak pernah kurang. Karenanya kesalahan terakumulasi.Jelek tapi berhasil. Anda mungkin harus memikirkan kembali desain program Anda jika Anda memerlukan loop seperti ini. Ini pada dasarnya memeriksa apakah seluruh detik saat ini sama dengan yang diperiksa sebelumnya dan mencetak jumlah nanodetik sejak pergantian detik. Akurasi dipengaruhi oleh tidur 0,001.
Akurasi dalam milidetik, asalkan 'payload'
date "+%N nanoseconds late"
tidak memakan waktu lebih lama dari hanya di bawah satu detik. Anda dapat menurunkan beban CPU dengan menambah periode tidur atau jika Anda benar-benar tidak keberatan cukup ganti perintah tidur dengantrue
.Ini adalah praktik buruk karena pada dasarnya Anda membuat jajak pendapat CPU untuk suatu acara dan Anda membuang-buang siklus CPU. Anda mungkin ingin melampirkan penghenti waktu (tidak mungkin dari bash) atau menggunakan perangkat keras khusus seperti mikrokontroler. PC dan sistem operasinya tidak dirancang untuk akurasi pengaturan waktu yang tinggi.
sumber
Metode lain adalah dengan menggunakan penangguhan dalam satu lingkaran dan mengirim SIGCONT dari program eksternal yang tepat. Mengirim sinyal sangat ringan dan memiliki latensi jauh lebih sedikit daripada mengeksekusi sesuatu. Anda juga dapat melakukan pra-antrian sekelompok perintah dengan perintah "at", hampir tidak ada yang menggunakan "at" lagi saya tidak yakin seberapa tepat itu.
Jika presisi sangat penting dan Anda ingin serius tentang ini, ini terdengar seperti jenis aplikasi di mana Anda biasanya akan menggunakan RTOS, yang dapat dilakukan di Linux dengan RT-Preempt patched kernel, yang akan memberi Anda presisi dan beberapa ukuran kontrol interupsi, tetapi mungkin lebih mengganggu daripada nilainya.
https://rt.wiki.kernel.org/index.php/RT_PREEMPT_HOWTO
Xenomai juga mungkin membantu, ini adalah implementasi RTOS penuh dan porting untuk x86 dan x86_64, tetapi ada beberapa pemrograman yang terlibat.
http://www.xenomai.org/index.php/Main_Page
sumber
Dengan
ksh93
(yang memiliki titik apung$SECONDS
dan builtinsleep
)Script yang sama akan bekerja dengan
zsh
baik tetapi akan menjalankansleep
perintah sistem Anda .zsh
memilikizselect
builtin, tetapi dengan resolusi 1/100 saja.sumber
Saya akan pergi dengan program C kecil:
Program ini mengharapkan program untuk memanggil dengan jalur penuh sebagai argumen pertama, dan meneruskan argumen yang tersisa. Itu tidak akan menunggu perintah selesai, jadi ia akan dengan senang hati memulai beberapa contoh.
Juga, gaya pengkodean di sini benar-benar ceroboh, dan sejumlah asumsi dibuat yang mungkin atau mungkin tidak dijamin oleh standar yang berlaku, yaitu kualitas kode ini "berfungsi untuk saya".
Program ini akan mendapatkan interval yang agak lebih lama atau lebih pendek ketika jam disesuaikan dengan NTP atau dengan mengaturnya secara manual. Jika program harus menangani ini, POSIX menyediakan
timer_create(CLOCK_MONOTONIC, ...)
yang tidak terpengaruh oleh ini.sumber
Anda harus melacak waktu saat ini dan membandingkannya dengan waktu mulai. Jadi Anda tidur dengan jumlah waktu yang dihitung setiap iterasi, bukan jumlah yang tetap. Dengan cara ini Anda tidak akan mengakumulasi kesalahan waktu dan bergeser dari tempat Anda seharusnya karena Anda mengatur ulang waktu Anda setiap loop ke waktu absolut dari awal.
Juga beberapa fungsi tidur kembali lebih awal jika ada interupsi, jadi dalam hal ini Anda harus memanggil metode tidur Anda lagi sampai waktu penuh telah berlalu.
sumber
Berikut ini adalah skrip bash dan sangat akurat. Ini menggunakan usleep untuk presisi mikrodetik.
http://wiki.junkemailfilter.com/index.php/How_to_run_a_Linux_script_every_few_seconds_under_cron
Ada 3 skrip di sana. Lihatlah yang di bawah. Akan melakukan hingga sekitar 2400 eksekusi per menit dengan akurasi yang wajar. Dan itu sangat sederhana.
sumber
Yang ini dapat berjalan setidaknya 100 kali per detik dengan resolusi yang sangat akurat.
Keberadaan direktori jumlah loop per menit menciptakan jadwal. Versi ini mendukung resolusi microsecond dengan anggapan komputer Anda dapat mengatasinya. Jumlah eksekusi per menit tidak harus dibagi rata dengan 60 atau terbatas pada 60 Saya telah mengujinya hingga 6000 dan berfungsi.
Versi ini dapat diinstal di direktori /etc/init.d dan dijalankan sebagai layanan.
sumber