Потрібна петля для сну на частку секунди


14

На своїй машині мені потрібно виконати цикл, який повторює 1 просту команду, яка повинна мати затримку, виражену частками секунди.

Скажімо, що мені потрібно:

  • щоб зберегти файл із збільшенням перерахунку (файл-0, файл-1, файл-2, ...), генерується чимось тривіальним для цього прикладу, наприклад time > file-$x
  • Мені потрібно робити це кожні 1/70 секунди (як приклад), тому що я хотів би виразити свій час дробами секунди.

Як я можу бути по-справжньому точним і все висловити баш-сценарієм?

Фракція може генерувати невизначену кількість, мені потрібно бути точним, і тому мені потрібно щонайменше 4-5 десятків.

Відповіді:


12

Щоб перетворити з дробів на десяткові числа в bash, зробіть щось подібне

myvar=$(echo "scale=4; 5/10" | bc)

Потім, щоб зробити цикл для цього значення,

for i in $(seq 1 1000); do sleep $myvar; done

Моя реалізація сну на Debian (GNU), схоже, приймає десяткові значення сну.

На жаль ..

З такою точністю (4-5 знаків після коми) вам потрібно щось схоже на сценарій perl або складену програму; накладні витрати на виклик будь-якої програми в циклі додадуть багато тремтіння. Виклик самого сну займе кілька мілісекунд.

Розглянемо наступне: 1/100000 другого сну, зробленого 1000 разів:

time for i in $(seq 1 1000); do sleep 0.0001; done

real    0m2.099s
user    0m3.080s
sys     0m1.464s

Очікуваний результат складе 1/10 секунди. Уві сні немає ніде потрібних допусків.

/programming/896904/how-do-i-sleep-for-a-millisecond-in-perl

використовуючи час Perl :: HiRes, 1000 * 1000 мікросекунд:

my $i=0;
for($i=0;$i<=1000;$i++) {
        usleep(1000);
}

real    0m1.133s
user    0m0.024s
sys     0m0.012s

дає нам набагато ближче до секунди.


якщо це неможливо досягти 4-5 десяткових знаків, я б взяв найкращий можливий результат як альтернативу, але моя думка полягає в тому, що мені потрібно виразити це дробами, а не десяткові дроби або секунди.
користувач1717079

Було б абсолютно тривіально перетворити дріб у десятковий на будь-якій мові сценаріїв, включаючи bash. наприклад відлуння "шкала = 4; 5/10" | bc
Роб Бос

тепер у мене з'явилося, як перетворити вираз, проблема в тому, що простий баш це дуже повільно і не може просто йти в ногу з цією частотою ...
user1717079

Так, якщо ви хочете чогось набагато точнішого, ніж приблизно 10/10 секунди, ви, мабуть, захочете perl або python, щоб уникнути виклику програми накладні в циклі.
Роб Бос

7

Можливо, ти можеш просто бігти

sleep 0.7

?

man 1 sleep

на мій archlinuxdistro:

ОПИС Пауза на NUMBER секунди. SUFFIX може бути "s" секундами (за замовчуванням), "m" хвилин, "h" годинами або "d" днями. На відміну від більшості реалізацій, для яких потрібно NUMBER бути цілим числом, тут NUMBER може бути довільним номером з плаваючою комою. Надаючи два чи більше аргументів, зробіть паузу на кількість часу, визначену сумою їх значень.


sleepдозволяє дроби? чи можете ви запропонувати повний приклад із підробленою петлею?
користувач1717079

0.7 - це не частка, яка виражає мою проблему ... моя проблема полягає в деталізації; подумайте про 1/3 і спробуйте бути акуратними зі сном.
користувач1717079

6

Нерестування процесу та завантаження в нього нового виконуваного файлу, ймовірно, займе кілька мілісекунд, тому така точність насправді не має сенсу. Також зауважте, що час процесора в багатьох системах розподіляється на процеси за допомогою фрагментів до 10 мс.

Сказавши це, деякі sleepреалізації займають дробові числа секунд, і zsh і ksh93 можуть зробити свою $SECONDSспеціальну змінну дробовою typeset -F SECONDS.

Приклад (zsh):

$ typeset -F SECONDS=0; for ((i=1; i<=70; i++)); do sleep $((1./70)); date +%s.%N; done | { head -n3;echo ..;tail -n3; }; echo $SECONDS
1350076317.374870501
1350076317.391034397
1350076317.407278461
..
1350076318.464585550
1350076318.480887660
1350076318.497133050
1.1393780000

На жаль, воно дрейфувало. Ви можете налаштувати час сну виходячи з $SECONDS:

$ typeset -F SECONDS=0; for ((i=1; i<=70; i++)); do sleep $((i/70. - SECONDS)); date +%s.%N; done | { head -n3;echo ...;tail -n3; }; echo $SECONDS
1350076420.262775654
1350076420.277012997
1350076420.291302750
../..
1350076421.219682227
1350076421.234134663
1350076421.248255685
1.0020580000

Ці 2 зайвих мілісекунди, ймовірно, слід враховувати для запуску останньої sleepта dateкоманд.

Також зауважте, що zsh має zselectвбудований тайм-аут, виражений у соті секунди. І ksh93 має sleepвбудований (і приймає плаваючі точки) і printfможе друкувати дату / час.

$ typeset -F SECONDS=0; for ((i=1; i<=70; i++)); do ((i<4 || i>67)) && printf '%(%S.%N)T\n' now; sleep $((i/70.-SECONDS)); done; echo $SECONDS
20.823349000
20.837510000
20.851663000
21.780099000
21.794254000
21.808405000
0.9992358685

Якщо ви хочете щось більш точне, ви, ймовірно, захочете операційну систему в режимі реального часу або операційну систему з можливостями в режимі реального часу і, звичайно, не використовувати оболонку.


sleep 1/70не дозволено на моїй машині ...
користувач1717079

навіть не поруч із тим, чого я хочу досягти, як я можу виконувати речі швидше?
користувач1717079

Вибачте, через дробові я не мав на увазі вираження як n / m, де n і m цілі числа, а як десяткові знаки з дробовою частиною. Я думаю, ви також можете назвати їх десятковими числами з плаваючою комою, хоча я не впевнений у правильній англійській термінології
Stéphane Chazelas

Я думаю, що я збираюся уникати оболонки ...
user1717079

Відповідач має рацію. Оболонки та процеси зазвичай не дуже підходять для роздільної здатності мілісекунд. Для надійної продуктивності вам потрібно буде скласти програму, яка викликає usleep (3) тощо), і вам може знадобитися перекомпілювати ваше ядро ​​з іншою конфігурацією; або принаймні подавати різні параметри до планувальника виконання ядра. Це нетривіально робити. Стандартна установка Debian зі стандартним ядром має обмежені можливості в режимі реального часу. Тим не менш, ви можете перевірити nice (1) команду; це може допомогти.
вт

3

Якщо ваша оболонка sleepне приймає дріб, використовуйте perl.

sleep_fraction() {
  /usr/bin/perl -e "select(undef, undef, undef, $1)"
}

sleep_fraction 0.01428

Якщо вам потрібно з’ясувати дріб, використовуйте echo "scale=5; 1/70" | bc


0

У програмі Alpine Linux (Busybox) ви можете циклічно працювати на мікросекунди usleep 10(еквівалентні 0.00001секунді)

GNU sleep підтримує частки секунди: sleep 0.00001

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.