В Python, как я могу поместить поток в сон до определенного времени?
Я знаю, что я могу заставить поток спать в течение определенного времени с помощью:
time.sleep(NUM)
Как я могу сделать поток sleep до 2AM? Должен ли я делать математику, чтобы определить количество секунд до 2AM? Или есть некоторая функция библиотеки?
(Да, я знаю о cron и эквивалентных системах в Windows, но я хочу спать с моим потоком в самом питоне и не полагаться на внешние сигналы стимула или процесса.)
Ответы
Ответ 1
Здесь предлагается решение с половинной задницей, которое не учитывает дрожание часов или настройку часов. См. Комментарии для способов избавиться от этого.
import time
import datetime
# if for some reason this script is still running
# after a year, we'll stop after 365 days
for i in xrange(0,365):
# sleep until 2AM
t = datetime.datetime.today()
future = datetime.datetime(t.year,t.month,t.day,2,0)
if t.hour >= 2:
future += datetime.timedelta(days=1)
time.sleep((future-t).seconds)
# do 2AM stuff
Ответ 2
import pause
from datetime import datetime
pause.until(datetime(2015, 8, 12, 2))
Ответ 3
Один из возможных подходов - спать в течение часа. Каждый час проверяйте, находится ли время в середине ночи. Если это так, приступайте к выполнению операции. Если нет, спите еще час и продолжайте.
Если пользователь должен был изменить свои часы в середине дня, этот подход будет отражать это изменение. Хотя для этого требуется немного больше ресурсов, это должно быть незначительным.
Ответ 4
Я попробовал "паузу" pacakage. Это не работает для Python 3.x. Из пакета пауз я извлек код, необходимый для ожидания до определенного времени и сделавшего следующий def.
def wait_until(execute_it_now):
while True:
diff = (execute_it_now - datetime.now()).total_seconds()
if diff <= 0:
return
elif diff <= 0.1:
time.sleep(0.001)
elif diff <= 0.5:
time.sleep(0.01)
elif diff <= 1.5:
time.sleep(0.1)
else:
time.sleep(1)
Ответ 5
Слегка рядом с исходным вопросом:
Даже если вы не хотите обманывать crontabs, если вы можете планировать скрипты python для этих хостов, вам может быть интересно запланировать задачи anacron? anacron главный дифференциатор к cron заключается в том, что он не полагается, что компьютер работает непрерывно. В зависимости от конфигурации системы вам могут потребоваться права администратора даже для таких запланированных пользователем задач.
Аналогичный, более современный инструмент - это выскочка, предоставляемая людьми Ubuntu: http://upstart.ubuntu.com/
У этого еще нет необходимых функций. Но планирование работы и замена анакрона - это запланированная функция. У этого есть довольно некоторая тяга из-за его использования как замена initd по умолчанию Ubuntu. (Я не связан с проектом)
Конечно, с уже предоставленным ответом вы можете закодировать одну и ту же функциональность в своем python script, и это может подойти вам лучше в вашем случае.
Тем не менее, для других анакрон или подобные существующие системы могут быть лучшим решением. anacron предварительно установлен во многих текущих дистрибутивах Linux (есть проблемы с переносимостью для пользователей Windows).
Википедия предоставляет страницу указателя: https://en.wikipedia.org/wiki/Anacron
Если вы собираетесь использовать версию python, я бы посмотрел асинхронный аспект и обеспечил работу script, даже если время изменится (переход на летнее время и т.д.), как уже прокомментировали другие. Вместо того, чтобы ждать до заранее рассчитанного будущего, я всегда буду ждать максимум один час, а затем повторю проверку времени. Вложенные расчетные циклы должны быть незначительными даже на мобильных, встроенных системах.
Ответ 6
адаптировать это:
from datetime import datetime, timedelta
from time import sleep
now = datetime.utcnow
to = (now() + timedelta(days = 1)).replace(hour=1, minute=0, second=0)
sleep((to-now()).seconds)
Ответ 7
Другой подход, использующий sleep
, логарифмически уменьшает время ожидания.
def wait_until(end_datetime):
while True:
diff = (end_datetime - datetime.now()).total_seconds()
if diff < 0: return # In case end_datetime was in past to begin with
time.sleep(diff/2)
if diff <= 0.1: return
Опираясь на ответ @MZA и комментарий @Mads Y
Ответ 8
Вместо использования функции wait() вы можете использовать цикл while, проверяющий, достигнута ли указанная дата:
if datetime.datetime.utcnow() > next_friday_10am:
# run thread or whatever action
next_friday_10am = next_friday_10am()
time.sleep(30)
def next_friday_10am():
for i in range(7):
for j in range(24):
for k in range(60):
if (datetime.datetime.utcnow() + datetime.timedelta(days=i)).weekday() == 4:
if (datetime.datetime.utcnow() + datetime.timedelta(days=i, hours=j)).hour == 8:
if (datetime.datetime.utcnow() + datetime.timedelta(days=i, hours=j, minutes=k)).minute == 0:
return datetime.datetime.utcnow() + datetime.timedelta(days=i, hours=j, minutes=k)
Тем не менее поток проверки времени проверяет состояние каждые 30 секунд, поэтому требуется больше вычислений, чем при ожидании, но это способ заставить его работать.
Ответ 9
Я знаю, что уже поздно для этого, но я хотел опубликовать ответ (вдохновленный отмеченным ответом), учитывая, что системы могут иметь - неправильный - желаемый часовой пояс +, включая, как это сделать, для людей, интересующихся как.
Это выглядит большим, потому что я комментирую каждый шаг, чтобы объяснить логику.
import pytz #timezone lib
import datetime
import time
from threading import Thread
# using this as I am, check list of timezone strings at:
## https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
TIMEZONE = pytz.timezone("America/Sao_Paulo")
# function to return desired seconds, even if it the next day
## check the bkp_time variable (I use this for a bkp thread)
## to edit what time you want to execute your thread
def get_waiting_time_till_two(TIMEZONE):
# get current time and date as our timezone
## later we remove the timezone info just to be sure no errors
now = datetime.datetime.now(tz=TIMEZONE).replace(tzinfo=None)
curr_time = now.time()
curr_date = now.date()
# Make 23h30 string into datetime, adding the same date as current time above
bkp_time = datetime.datetime.strptime("02:00:00","%H:%M:%S").time()
bkp_datetime = datetime.datetime.combine(curr_date, bkp_time)
# extract the difference from both dates and a day in seconds
bkp_minus_curr_seconds = (bkp_datetime - now).total_seconds()
a_day_in_seconds = 60 * 60 * 24
# if the difference is a negative value, we will subtract (- with + = -)
# it from a day in seconds, otherwise it just the difference
# this means that if the time is the next day, it will adjust accordingly
wait_time = a_day_in_seconds + bkp_minus_curr_seconds if bkp_minus_curr_seconds < 0 else bkp_minus_curr_seconds
return wait_time
# Here will be the function we will call at threading
def function_we_will_thread():
# this will make it infinite during the threading
while True:
seconds = get_waiting_time_till_two(TIMEZONE)
time.sleep(seconds)
# Do your routine
# Now this is the part where it will be threading
thread_auto_update = Thread(target=function_we_will_thread)
thread_auto_update.start()
Ответ 10
from datetime import datetime
import time, operator
time.sleep([i[0]*3600 + i[1]*60 for i in [[H, M]]][0] - [i[0]*3600 + i[1]*60 for i in [map(int, datetime.now().strftime("%H:%M").split(':'))]][0])