В статье будет решаться следующая задача: Сделать приложение которое будет показывать время прошедшее с момента включения приложения с его обновлением 1 раз в секунду.
1.Очевидное стандартное решение.
Создаем стандартный таймер и выводим его тики.
timeout = 1000 timer.performWithDelay( timeout,function(event) print(event.count) end,0)
Вроде бы все очевидно, но в работе этого решения есть особенности:
- Во-первых стандартный таймер способен корректно и достаточно точно отрабатывать таймауты начиная с 300-400мс, а все что ниже этого значения начинает очень существенно отставать, но наш случай другой так как таймаут более указанных пределов. Минимально возможный период тиков таймера (если указать 1 мс) будет составлять 10-50мс причем с большим разбросом от тика к тику.
- Во-вторых даже на указанном относительно точном периоде имеется случайная погрешность около 5-10 мс с каждого тика, т.е. за час набегает погрешность 15-30секунд. Эту проблему частично можно решить отняв 5 мс от того значение которое указывается в параметре при создании таймер, т.е. вместо 1000 указать 995.
- В-третьих если в вашем приложении будут возникать мелкие фризы вызванные результатом работы другого кода или нестабильной работой устройства, эти фризы так же будут добавляться в копилку отставания в работе таймера.
- В четвертых если свернуть приложение на какое-то время и после этого его заново развернуть, все время которое приложение было свернуто будет исключено из количества секунд работы приложения.
2. Хорошее решение.
Для решения проблем прошлого способа используем следующую конструкцию, в этом методе мы применяем таймер с максимально возможной скорость, но сигналом для тика таймер будет расчет опирающийся на источник точного времени системы.
local timeout = 1000--таймаут socket = require "socket" local start_time = socket.gettime()*1000--время инициализации таймера(старт приложения) local good_time = 0 timer.performWithDelay( 1,function(event) local new_time = socket.gettime()*1000--новая временная метка local total_time = new_time - start_time--прошло времени с момента запуска приложеня local num = math.floor(total_time/timeout)--количество прошедших целых периодов размером в timeout if num > good_time then--если пришло время нового тика good_time = num--новый тик print(good_time) end end,0)
Разбираем особенности этого метода. Несмотря на то что мы указываем частоту тиков 1мс как было описано выше реальные кванты тиков будут выполняться с раз в 10-50мс, а это и будет определять максимально возможную погрешность приведенного выше метода, погрешность будет изменяться в диапазоне 0..50мс от тика к тику, т.е. частота следования тиков будет менее стабильной чем в первом методе, но величина этой погрешности на любой дистанции (даже длиной в годы) будет одинаковой, т.е. даже через год наш очередной тик будет иметь погрешность в этих же пределах относительно самого первого тика.
3. Проверка результатов
Приведу пример того как можно проверить справедливость всего выше сказанного. Приведенный исходник будет раз в секунду выводить текущее время прошедшее с момента включения приложения для двух таймеров(отдельно) и показывать накопленную за время работы ошибку.
local timeout = 1000 socket = require "socket" local start_time = socket.gettime()*1000--время инициализации таймера local good_time = 0--время сокетного счетчика local bad_time = 0--время обычного счетчика --плохой таймер timer.performWithDelay( timeout,function(event) bad_time = event.count local bad_delta = (socket.gettime()*1000 - start_time) - (bad_time*timeout) print('Bad tick: '..bad_time, 'Delta: '..bad_delta) end,0) --хороший таймер timer.performWithDelay( 1,function(event) local new_time = socket.gettime()*1000 local total_time = new_time - start_time local num = math.floor(total_time/timeout) if num > good_time then good_time = num local good_delta = (socket.gettime()*1000 - start_time) - (good_time*timeout) print('Good tick: '..good_time, 'Delta: '..good_delta) end end,0)
Всем удачи!
ссылка на оригинал статьи https://habr.com/post/422443/
Добавить комментарий