Как сделать равные задержки в коде на 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
root
 12 сентября 2020 в 22:12 
  5  

423077
2020-09-12 22:12:56
root     12 октября 2021 в 21:45 Ответить
Test


Комментировать



Опубликовать запись
В этой строке мы предупреждаем Вас, что можем использовать так называемые cookies
Нам искренне плевать на введенную Вами информацию о себе. Мы просто запоминаем у Вас на устройстве то, что Вы же и настроили.