Python在特定时间开始一个进程并在特定时间结束它

时间:2019-02-22 11:08:54

标签: python python-multithreading

这是一个示例python代码,每5秒运行一次进程,直到凌晨1点。

def run_check():
  mythrd =threading.Timer(5.0, run_check)
  mythrd.start()
  time = datetime.now()
  domystuff()

  if time.hour == 1:
    mythrd.cancel()

run_check()

我想在特定时间启动线程。所以我如下更改了代码,

mythrd = None

def run_check():
  while (True):

    now = datetime.now
    if now().hour == 16 and now().minute == 30 and now().second == 30:
      mythrd.start()
      time.sleep(1)
    if mythrd.is_alive():
      domystuff()

    if datetime.now().hour == 16 and datetime.now().minute == 31:
        mythrd.cancel()

mythrd =threading.Timer(5.0, run_check)
run_check()

之前,我将mythrd对象保留在run_check函数中。如果我在run_check函数中初始化,它将把该对象用作新对象。并且它将再次触发。因此,我将mythrd函数定义为全局对象。但是它一直在运行。我想在特定时间开始该过程,并在特定时间结束它。我的代码有什么问题?

2 个答案:

答案 0 :(得分:2)

此代码存在几个问题。 首先,当在线程内部循环且没有条件发生时,请添加睡眠以节省CPU使用率。 其次,由于线程是不确定的,因此无法在确切的时间戳上触发条件。例如,线程可能会在“热”时间间隔内跳过其执行,并且该条件永远不会触发。

因此,您可以改为检查当前时间戳是否已经过某个时间戳(以及经过了多少时间)和/或比较时间戳。

但是无论如何,mythrd在代码中启动了一个线程函数,该函数将递归调用自身。...这就是问题所在。

mythrd =threading.Timer(5.0, run_check)

然后

mythrd.start()  # will start threading.Timer(5.0, run_check)

因此,当条件now().hour == 16 and now().minute == 30 and now().second == 30触发时,线程将运行其自身的另一个实例。此实例可能会运行另一个实例,依此类推...

您是要实现触发线程,执行run_check任务,然后再启动另一个线程来执行实际工作吗?

这是一个解决方案:

from threading import Thread, Timer
import time
import datetime

keep_checking = True
keep_working = True

def worker_thread():
    while keep_working:
        pass #do my stuff here and remember to use an eventual sleep

def time_checker():
    while keep_checking:
        now = datetime.now()
        if now.hour == 16 and now.minute == 30 and (
           now.second >= 30 and now.second < 31) and (
           not mythrd.isAlive()):
            mythrd.start()
        elif now.minute >= 31 and mythrd.isAlive():
            keep_working = False # and let it die instead to kill it
        else:
            time.sleep(1) # no operation

mythrd = threading.Thread(target=worker_thread)
time_checker() # might turn this into a thread as well

请记住,您需要定义线程打开和关闭的确切时间间隔。有条件地涵盖所有这些情况,并采取相应的行动。随着您的项目变得越来越复杂,可能需要稍后使用互斥体。

答案 1 :(得分:1)

我已经为您实现了此解决方案:

from datetime import datetime as dt
import threading
import time

class test(object):

    def __init__(self):
        self.run_permission = False

        self.start_time = [16,30,30] # Hours, Minutes, Seconds
        self.end_time = [18,41,00] # Hours, Minutes, Seconds

        self.timer_sched_time = 5 # seconds

        threading.Thread(name="time_checker", target=self.check_time, args=(self.start_time, self.end_time,)).start()
        threading.Thread(name="scheduled_job", target=self.Timer, args=(self.timer_sched_time, )).start()

        while True:
            time.sleep(10)

    def timer_job(self, unix_time, human_time):
        print "Unix time: %s  Human time: %s \n" % (unix_time, human_time)

    def Timer(self, delay):
        while True:
            try:
                time_remaining = delay-time.time()%delay
                time.sleep(time_remaining)

                unix_time = str(int(round(time.time()*1000)))
                human_time = str(dt.now())

                if(self.run_permission):
                    self.timer_job(unix_time, human_time)

            except Exception, ex:
                raise ex

    def check_time(self, start_execution_time, end_execution_time):
        while True:
            now = dt.now()

            if(now.hour >= start_execution_time[0] and now.minute >= start_execution_time[1] and now.second >= start_execution_time[2]):
                self.run_permission = True

            if(now.hour >= end_execution_time[0] and now.minute >= end_execution_time[1] and now.second >= end_execution_time[2]):
                self.run_permission = False

test()

首先,导入所需的库:

from datetime import datetime as dt
import threading
import time

创建一个名为test的类:

class test(object):

确定__init__,当您使用test()调用类测试时,它将在创建类测试时执行:

def __init__(self):
        self.run_permission = False

        self.start_time = [16,30,30] # Hours, Minutes, Seconds
        self.end_time = [18,41,00] # Hours, Minutes, Seconds

        self.timer_sched_time = 5 # seconds

        threading.Thread(name="time_checker", target=self.check_time, args=(self.start_time, self.end_time,)).start()
        threading.Thread(name="scheduled_job", target=self.Timer, args=(self.timer_sched_time, )).start()

        while True:
            time.sleep(10)

变量run_permission是一个布尔值,用作检查是否可以在计时器中执行作业的标志。

start_time变量设置check_time例程的开始时间,该例程将run_permission变量写入True(如果时间很长或等于{{1}) }

start_time变量设置end_time例程的停止时间,该例程将check_time变量写入False,如果该时间是主变量或等于run_permission

end_time变量设置了计时器的延迟,该延迟是计算睡眠时间所需要的,它每5秒授予一次完美的时间执行:17.00.00-17.00.05-17.00.10-17.00 .15等等等

以下两行将启动timer_sched_time作业和check_time作业的线程:

Timer

这两行代码使Main线程保持运行状态,但是休眠主线程以减少资源消耗:

threading.Thread(name="time_checker", target=self.check_time, args=(self.start_time, self.end_time,)).start()
threading.Thread(name="scheduled_job", target=self.Timer, args=(self.timer_sched_time, )).start()

函数while True: time.sleep(10) 仅以Unix格式和人类可读格式打印时间:

timer_job

要翻译Unix格式,您可以使用epoch converter website

def timer_job(self, unix_time, human_time): print "Unix time: %s Human time: %s \n" % (unix_time, human_time) 函数计算睡眠时间以将执行授予最佳时间,采用unix和人类格式的时间戳,如果Timer变量将其传递给timer_job设置为run_permission

True

如果遵守时间执行条件,则check_time函数使用参数def Timer(self, delay): while True: try: time_remaining = delay-time.time()%delay time.sleep(time_remaining) unix_time = str(int(round(time.time()*1000))) human_time = str(dt.now()) if(self.run_permission): self.timer_job(unix_time, human_time) except Exception, ex: raise ex _time和start_execution将变量end_execution_time设置为run_permissionTrue(因此,如果遵守小时/分钟/秒的范围):

False

如前所述,文件末尾的def check_time(self, start_execution_time, end_execution_time): while True: now = dt.now() if(now.hour >= start_execution_time[0] and now.minute >= start_execution_time[1] and now.second >= start_execution_time[2]): self.run_permission = True if(now.hour >= end_execution_time[0] and now.minute >= end_execution_time[1] and now.second >= end_execution_time[2]): self.run_permission = False 调用测试类,并使用test()函数初始化程序。