Как сделать равные задержки в коде на PHP
Умный дом / PHP / Raspberry Pi / Сделай сам Оговорюсь сразу, в основном это касается системного программирования на PHP, которое хоть и сложно, но возможно. То есть речь не о Web.
Представьте себе ситуацию, когда у вас бесконечно работает PHP-скрипт, который в определенные промежутки времени должен делать определенное действие, к примеру выборку, неважно откуда - от датчика, с удаленного сайта, и тд. Важно одно - равные промежутки времени.
Вот например как мы сделаем упрощенный счетчик электричества. Раз в секунду будем дергать датчик потребления тока, наберем 3600 значений (столько секунд в часе), потом посчитаем среднее арифметическое, и получим сколько киловатт в час мы потребили. Казалось бы, ничего сложного - считали, записали, секунду подождали, и так до бесконечности.
<?php
$i=0;
$c=0;
while (1==1) {
$c=$c+get_value();
$i++;
if ($i==3600) {$kwh=$c/3600;echo "$kwh час потреблено";$i=0;$c=0;}
usleep(1000000);
}
?>
На первый взгляд этот простой код, каждый час будет выводить среднее арифметическое того, что мы получали в течение часа функцией get_value().
Но на самом деле, это будет не так. Эта самая функция будет наверняка дергать какой-то физический порт, ответ с которого может приходить с разной скоростью, равно как время потребует вывод команды echo. Конечно, это будут миллисекунды, но общий смысл в том, что пауза при каждой итерации будет не 1с, а к примеру 1.03с, в следующий раз 1.1 с, а иногда и вовсе 1с как и планировалось. Вроде бы мелочи, но погрешность в расчете электричества в пределах 30 дней, будет составлять десятки гривен. И это только самый простой пример, как неравномерная секунда может сыграть злую шутку с кошельком.
Самый простой способ который пришел мне в голову дабы сделать промежуток между итерациями практически равным секунде - просто замерять время выполнения скрипта от начала блока, до собственно самой функции паузы, и расчитывать значение паузы опираясь на уже затраченное время.
К примеру, если функция get_value() получила значение с порта за 300мс, то функция sleep должна ожидать уже не 1000мс, а 700мс.
Тогда наш код превращается в такой:
<?php
$i=0;
$c=0;
while (1==1) {
$start_time=microtime(true);
$c=$c+get_value();
$i++;
if ($i==3600) {$kwh=$c/3600;echo "$kwh час потреблено";$i=0;$c=0;}
$gone_time=round(microtime(true)-$start_time,3);
$delay=(1.00-$gone_time)*1000000;
if ($delay<0) {$delay=0;}
usleep($delay);
}
?>
Не правда ли изящно-костыльное решение ?Метки текста: Стабильный usleep
https://minidevices.top/images/ava.png
https://minidevices.top/images/ava.png
2020-09-12 22:12:56
2020-09-12 22:12:56
root
12 сентября 2020 в 22:12
♡ 5 ♡
423173
2020-09-12 22:12:56
root