Как сделать таймер в python
Python: как сделать многопоточную программу
У такой схемы есть минус: мы не можем пользоваться программой и выделенными на неё ресурсами до тех пор, пока она не проснётся. Процессор по кругу гоняет пустые команды и ждёт, когда можно будет продолжить полезную работу. Чтобы процессор и программа могли во время работы таймера делать что-то ещё, используют потоки.
Что такое поток
В упрощённом виде потоки — это параллельно выполняемые задачи. По умолчанию используется один поток — это значит, что программа делает всё по очереди, линейно, без возможности делать несколько дел одновременно.
Но если мы сделаем в программе два потока задач, то они будут работать параллельно и независимо друг от друга. Одному потоку не нужно будет становиться на паузу, когда в другом что-то происходит.
👉 Важно понимать, что поток — это высокоуровневое понятие из области программирования. На уровне вашего «железа» эти потоки всё ещё могут обсчитываться последовательно. Но благодаря тому, что они будут обсчитываться быстро, вам может показаться, что они работают параллельно.
Многопоточность
Представим такую ситуацию:
А теперь давайте посмотрим, как это выглядит в однопоточной и многопоточной системе. Видно, что если процессор позволяет делать несколько дел одновременно, в многопоточном режиме программа будет работать быстрее:
Многопоточность на Python
За потоки в Python отвечает модуль threading, а сам поток можно создать с помощью класса Thread из этого модуля. Подключается он так:
from threading import Thread
После этого с помощью функции Thread() мы сможем создать столько потоков, сколько нам нужно. Логика работы такая:
Для иллюстрации запустим такой код:
А вот как выглядит результат. Обратите внимание — потоки просыпаются не в той последовательности, как мы их запустили, а в той, в какой их выполнил процессор. Иногда это может помешать работе программы, но про это мы поговорим отдельно в другой статье.
Добавляем потоки в таймер
Первое, что нам нужно сделать, — вынести код таймера-напоминания в отдельную функцию, чтобы создать с ней поток. Для этого используем команду def :
Теперь сделаем новый поток, в который отправим выполняться нашу новую функцию. Так как аргументов у нас нет, то и аргументы передавать не будем, а напишем args=().
# Создаём новый поток
th = Thread(target=remind, args=())
Нам осталось убедиться в том, что пока поток работает, мы можем выполнять в программе что-то ещё и наше засыпание в потоке на это не повлияет. Для этого мы через 20 секунд после запуска выведем сообщение на экран. За 20 секунд пользователь успеет ввести напоминание и время, после чего таймер уйдёт в новый поток и там уснёт на нужное количество минут. Но это не помешает работе основной программы — она тоже будет выполнять свои команды параллельно с потоком.
# Пока работает поток, выведем что-то на экран через 20 секунд после запуска
print(«Пока поток работает, мы можем сделать что-нибудь ещё.\n»)
Как работает timeit в Python?
Модуль Python timeit — это простой интерфейс для быстрого измерения времени выполнения небольших блоков кода.
Когда вы создаете приложение, вы можете задаться вопросом, как этот блок кода будет работать, и захотите протестировать его в различных сценариях.
Для этого модуль timeit предоставляет очень простое решение этой проблемы. Давайте посмотрим, как мы можем использовать это для синхронизации наших фрагментов кода.
Мы рассмотрим как интерфейс командной строки, так и вызываемый интерфейс.
Python timeit — интерфейс командной строки
Интерфейс командной строки очень похож на интерфейс запуска программы Python.
По умолчанию это будет запускать код 1 миллион раз в Linux и 20 миллионов раз в Windows и измерять лучшее время среди этих значений. Ниже приведены результаты моей системы Linux.
Обратите внимание, что если у вас уже есть цикл for в вашем фрагменте, модуль гарантирует, что общее количество итераций близко к 1 миллиону, поэтому весь ваш цикл не будет выполняться 1 миллион раз.
Мы также можем использовать timeit через интерпретатор Python и импортировать его, используя:
Использование модуля
Давайте теперь посмотрим, как мы можем использовать timeit для timeit времени сниппета внутри нашей программы.
Что, если ваш код требует предварительной настройки? А если вам тоже нужно импортировать определенные модули?
Что ж, решение этой проблемы — использовать блок кода настройки, который выполнит всю необходимую работу по настройке всех необходимых модулей и переменных.
Написать блок настройки очень просто. Вы просто пишете любой код, который вам нужен, и передаете его в виде строки в переменную.
timeit гарантирует, что настройка будет выполнена до измерения вашего основного цикла, поэтому он выполняется только один раз.
Этот код пытается получить все подмассивы из начального элемента массива numpy. Обратите внимание, что блок настройки запускается только один раз.
Сравните производительность блоков кода
Время, затрачиваемое на блок кода, будет текущим временем минус начальное время, взятое за эталон, которое вы можете передавать через переменные.
Давайте протестируем 2 функции в массиве numpy range() и np.arange() и посмотрим, как они сравниваются.
Таким образом, мы могли легко использовать timeit для сравнения производительности различных функций.
Время для конкретной функции
Мы также можем рассчитать время выполнения определенной функции в сценарии, не выполняя другие блоки кода.
Работа с модулем времени(time) в Python
Модуль времени Python предоставляет нам различные функции для внедрения системного времени в наше приложение с помощью сценариев.
Чтобы начать работу с модулем времени, нам нужно импортировать его в наш скрипт python, используя следующую инструкцию:
При выполнении операций с данными, относящимися к метке времени, необходимо иметь отправную точку, с которой мы можем начать выполнять операции с ними.
Эпоха — это начальная точка времени, от которой следует отсчитывать время.
Функции модуля времени Python
Модуль времени Python предлагает хороший набор функций для работы с отметкой времени.
Ниже приведены наиболее часто используемые функции:
1 метод time.time()
В модуле времени Python есть метод time.time() который дает секунды текущего местного времени.
2 метод time.sleep()
Метод time.sleep() обеспечивает интервал времени или задержку между выполнением текущих процессов или потоков.
В приведенном выше фрагменте кода, когда мы пытаемся выполнить приведенный выше код, можно легко наблюдать задержку, пока операторы вывода отображаются на консоли.
3 метод time.localtime()
Модуль времени Python содержит класс struct_time, доступ к которому можно получить с помощью различных функций. Это помогает нам получить доступ к различным полям местной метки времени, таким как год, час, секунды и т. д.
Класс struct_time состоит из следующих атрибутов:
Функция time.localtime() запускает функцию time.time() в серверной части и возвращает детали текущего времени в формате класса struct_time по местному времени.
Мы также можем передать количество секунд с начала эпохи в качестве аргумента функции.
4 метод time.ctime()
Метод time.ctime() принимает значение секунд с начала или результат функции time() в качестве аргумента и возвращает строковое значение, представляющее текущее местное время.
5 Метод time.mktime()
Метод time.mktime() является обратным методу time.localtime().
Он принимает struct_time (все кортежи класса struct_time) в качестве аргумента и возвращает время в секундах, которое прошло с начала.
В приведенном выше примере мы использовали метод locatime() для получения кортежей класса struct_time и передали его методу mktime().
6 Метод time.gmtime()
Функция time.gmtime() запускает функцию time.time() в серверной части и возвращает детали текущего времени в формате класса struct_time в UTC.
7 метод time.strptime()
Метод time.strptime() принимает строку, представляющую время, и возвращает сведения о времени в формате struct_time.
Как правильно сделать временный цикл?
Нужно сделать цикл, который будет минуту выполнять функцию с промежутком в 1 сек.
Какой способ самый эффективный? Не смог придумать ничего лучше этого:
4 ответа 4
Можно range(n) использовать, чтобы повторить что-то n раз в Питоне:
«Правильный» и «эффективный» ли это способ? Это зависит от конкретной задачи.
Код прост и понятен: вызвать do_something() функцию 60 раз, каждый следующий вызов происходит не ранее чем через секунду после завершения предыдущего вызова. В конце ждём секунду прежде чем завершить цикл.
Представьте do_something() требует полсекунды в среднем, тогда цикл займёт полторы минуты или больше. Хорошо ли это—зависит от задачи.
Если вы хотите, чтобы вызовы происходили бы на границе каждой секунды:
C точностью до активности других процессов, потоков (особенностей планировщиков процессов/потоков в операционной системе, особенностей GIL реализации выбранной версии Питон-интерпретатора), каждый вызов do_something() кроме первого происходит близко ко времени, когда time.time() целые значения возвращает.
К примеру, если time.time() вернёт X.3 секунд, то time.sleep() будет спать не менее 0.7 секунд (если обработчик сигналов исключение не выбросит) и значит следующий вызов do_something() произойдёт в X + 1 секунд по системному времени (если оно сильно не прыгнуло пока мы спали). В этом случае вызовы do_something() могут быть более равномерно распределены и цикл завершится почти ровно через минуту согласно time.time() (если время выполнения do_something() менее секунды). Хорошо ли это—зависит от задачи.
Вещи, которые необходимо принять во внимание в зависимости от задачи:
К примеру, если время изменится во время выполнения print_some_times() из @ReinRaus ответа, то что по вашему произойдёт? Гарантированно ли это поведение документацией sched модуля (не изменится ли оно между разными реализациями/версиями Питона)? Важно ли это в вашем конкретном случае? (думаю, ясность простого цикла со sleep() может стать особенно привлекательной в этот момент).
В качестве вариации на тему, можно периодически вызывать функцию в фоновом потоке или использовать возможности различных циклов событий. В более сложных случаях, если у вас нет особых предпочтений, можно использовать apscheduler модуль, чтобы встроить планировщик в ваше приложение. В каких-то случаях имеет смысл воспользоваться планировщиком системы (для больших интервалов) таких как cron и Windows Task Scheduler.
I want to fire off a function every 0.5 seconds and be able to start and stop and reset the timer. I’m not too knowledgeable of how Python threads work and am having difficulties with the python timer.
However, I keep getting RuntimeError: threads can only be started once when I execute threading.timer.start() twice. Is there a work around for this? I tried applying threading.timer.cancel() before each start.
13 Answers 13
The best way is to start the timer thread once. Inside your timer thread you’d code the following
In the code that started the timer, you can then set the stopped event to stop the timer.
Using timer threads-
this can be stopped by t.cancel()
Improving a little on Hans Then’s answer, we can just subclass the Timer function. The following becomes our entire «repeat timer» code, and it can be used as a drop-in replacement for threading.Timer with all the same arguments:
produces the following output:
In the interest of providing a correct answer using Timer as the OP requested, I’ll improve upon swapnil jariwala’s answer:
I have changed some code in swapnil-jariwala code to make a little console clock.
Timer with a tkinter Graphic interface
This code puts the clock timer in a little window with tkinter
An example of flashcards game (sort of)
I had to do this for a project. What I ended up doing was start a separate thread for the function
****heartbeat is my function, worker is one of my arguments****
inside of my heartbeat function:
So when I start the thread the function will repeatedly wait 5 seconds, run all of my code, and do that indefinitely. If you want to kill the process just kill the thread.
I have implemented a class that works as a timer.
Here is small sample, it will help beter understanding how it runs. function taskManager() at the end create delayed function call to it self.
Try to change «dalay» variable and you will able to see difference
I like right2clicky’s answer, especially in that it doesn’t require a Thread to be torn down and a new one created every time the Timer ticks. In addition, it’s an easy override to create a class with a timer callback that gets called periodically. That’s my normal use case:
This is an alternate implementation using function instead of class. Inspired by @Andrew Wilkins above.
Because wait is more accurate than sleep ( it takes function runtime into account ):
I have come up with another solution with SingleTon class. Please tell me if any memory leakage is here.
clock starts at: 1602438840.9690785
timer_1 1602438845.980087
timer_2 1602438850.9806316
timer_1 1602438850.9808934
timer_1 1602438855.9863033
timer_2 1602438860.9868324
timer_1 1602438860.9876585