В статье будет решаться следующая задача: Сделать приложение которое будет показывать время прошедшее с момента включения приложения с его обновлением 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)
Всем удачи!
- Метки: