Подтвердить что ты не робот

В Python, как я могу поместить поток в сон до определенного времени?

Я знаю, что я могу заставить поток спать в течение определенного времени с помощью:

time.sleep(NUM)

Как я могу сделать поток sleep до 2AM? Должен ли я делать математику, чтобы определить количество секунд до 2AM? Или есть некоторая функция библиотеки?

(Да, я знаю о cron и эквивалентных системах в Windows, но я хочу спать с моим потоком в самом питоне и не полагаться на внешние сигналы стимула или процесса.)

4b9b3361

Ответ 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])