В Python, как я могу положить поток спать до определенного времени? - PullRequest
35 голосов
/ 09 января 2010

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

time.sleep(NUM)

Как я могу заставить поток спать до 2 часов ночи? Нужно ли делать математику, чтобы определить количество секунд до 2:00? Или есть какая-то библиотечная функция?

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

Ответы [ 10 ]

39 голосов
/ 09 января 2010

Вот наполовину решение, которое не учитывает дрожание часов или их настройку. Смотрите комментарии, чтобы узнать, как избавиться от этого.

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
21 голосов
/ 11 августа 2015
import pause
from datetime import datetime

pause.until(datetime(2015, 8, 12, 2))
5 голосов
/ 09 января 2010

Один из возможных подходов - спать в течение часа. Каждый час проверяйте, не пришло ли время среди ночи. Если так, продолжайте свою операцию. Если нет, поспите еще час и продолжайте.

Если бы пользователь менял свои часы в середине дня, этот подход отражал бы это изменение. Хотя это требует немного больше ресурсов, оно должно быть незначительным.

3 голосов
/ 13 сентября 2015

Я попробовал pacakage "пауза". Это не работает для Python 3.x. Из пакета pause я извлек код, необходимый для ожидания определенной даты, и сделал следующее определение.

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)
2 голосов
/ 12 октября 2011

Немного не относится к исходному вопросу:

Даже если вы не хотите возиться с crontabs, если вы можете запланировать сценарии python для этих хостов, вас может заинтересовать планирование задач anacron? Основным отличием anacron от cron является то, что он не полагается на непрерывную работу компьютера. В зависимости от конфигурации системы вам могут потребоваться права администратора даже для таких задач, запланированных пользователем.

Подобный, более современный инструмент - выскочка, предоставляемая людьми из Ubuntu: http://upstart.ubuntu.com/ Это еще даже не имеет необходимых функций. Но планирование заданий и замена анакрона - запланированная функция. Он имеет некоторую тягу благодаря использованию в качестве замены initd по умолчанию в Ubuntu. (Я не связан с проектом)

Конечно, с уже предоставленным ответом вы можете закодировать ту же функциональность в своем скрипте Python, и она может подойти вам лучше.

Тем не менее, для других, анакрон или аналогичные существующие системы могут быть лучшим решением. anacron предустановлен во многих текущих дистрибутивах Linux (существуют проблемы с переносимостью для пользователей Windows).

Википедия предоставляет страницу указателя: https://en.wikipedia.org/wiki/Anacron

Если вы выберете версию Python, я посмотрю на асинхронный аспект и убедимся, что скрипт работает, даже если время изменилось (переход на летнее время и т. Д.), Как уже прокомментировали другие. Вместо того, чтобы ждать заранее рассчитанного будущего, я всегда буду ждать максимум один час, а затем перепроверять время. Затраченные вычислительные циклы должны быть незначительными даже в мобильных встроенных системах.

1 голос
/ 04 апреля 2019

Адаптируйте это:

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)
0 голосов
/ 06 июня 2019

Я знаю, что уже поздно для этого, но я хотел опубликовать ответ (вдохновленный отмеченным ответом), учитывая, что системы могут иметь - неправильный - желаемый часовой пояс +, включая, как это сделать, для людей, задающихся вопросом, как.

Это выглядит большим, потому что я комментирую каждый шаг, чтобы объяснить логику.

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's 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's 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()
0 голосов
/ 13 мая 2019

Вместо использования функции 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 секунд, поэтому требуется больше вычислений, чем при ожидании, но это способ заставить его работать.

0 голосов
/ 19 февраля 2019

Другой подход, использующий 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

0 голосов
/ 04 октября 2014
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])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...