![](/img/trans.png)
[英]how to make a process sleep without making other processes sleep in python multiprocessing
[英]Python sleep without blocking other processes
我每小时运行一个 python 脚本,并且我一直在 while 循环中使用time.sleep(3600)
。 它似乎可以根据需要工作,但我担心它会阻止新任务。 我对此的研究似乎是它只阻塞了当前线程,但我想 100% 确定。 虽然每小时的工作不应该超过 15 分钟,但如果它完成或挂起,我不希望它阻止下一个开始的工作。 这就是我的做法:
import threading
import time
def long_hourly_job():
# do some long task
pass
if __name__ == "__main__":
while True:
thr = threading.Thread(target=long_hourly_job)
thr.start()
time.sleep(3600)
这足够了吗?
此外,我将time.sleep
用于这个每小时工作而不是 cron 工作的原因是我想在代码中做所有事情以使 dockerization 更清洁。
该代码将起作用(即: sleep
只会阻塞调用线程),但您应该注意一些问题。 其中一些已经在评论中说明,例如线程之间时间重叠的可能性。 主要问题是您的代码正在慢慢泄漏资源。 创建线程后,操作系统会保留一些数据结构,即使在线程完成运行后也是如此。 这是必要的,例如保持线程的退出状态直到线程的创建者需要它。 清除这些结构(概念上相当于关闭文件)的 function 称为join
。 已完成运行且未join
的线程称为“僵尸线程”。 这些结构所需的 memory 的数量非常少,并且对于任何合理数量的可用 RAM,您的程序应该运行几个世纪。 不过,加入您创建的所有线程是一个很好的做法。 一个简单的方法(如果您知道 3600 秒足以让线程完成)是:
if __name__ == "__main__":
while True:
thr = threading.Thread(target=long_hourly_job)
thr.start()
thr.join(3600) # wait at most 3600 s for the thread to finish
if thr.isAlive(): # join does not return useful information
print("Ooops: the last job did not finish on time")
如果您认为有时 3600 秒可能不足以让线程完成,则可以使用更好的方法:
if __name__ == "__main__":
previous = []
while True:
thr = threading.Thread(target=long_hourly_job)
thr.start()
previous.append(thr)
time.sleep(3600)
for i in reversed(range(len(previous))):
t = previous[i]
t.join(0)
if t.isAlive():
print("Ooops: thread still running")
else:
print("Thread finished")
previous.remove(t)
我知道print
语句没有意义:改用logging
。
也许有点晚了。 我从其他答案中测试了代码,但我的主要过程卡住了(也许我做错了什么?)。 然后我尝试了一种不同的方法来模拟 QtCore.QTimer() 行为。 我认为它不是非常精确,它仍然包含一个 time.sleep() 语句,但要短得多,因此它不会阻塞主进程(至少不显着):
import threading
import time
import traceback
class Timer:
SNOOZE = 0
ONEOFF = 1
def __init__(self, timerType=SNOOZE):
self._obj = self._Counter()
self._kill = threading.Event()
self._timerType = timerType
self._msec = 0
self._thread = None
self._function = None
class _Counter:
def __init__(self):
super().__init__()
def run(self, quit_event: threading.Event(), msec: int, callback):
endTime = round(time.time() * 1000) + msec
while round(time.time() * 1000) < endTime and not quit_event.is_set():
time.sleep(0.001)
if not quit_event.is_set():
callback()
def start(self, msec, callback):
self._function = callback
self._msec = msec
if self._function and hasattr(self._function, '__call__') and msec > 0:
self._thread = threading.Thread(target=self._obj.run, args=(self._kill, self._msec, self._callback))
self._thread.setDaemon(True)
self._thread.start()
def _callback(self):
try:
self._function()
if self._timerType == self.SNOOZE:
self.start(self._msec, self._function)
except:
tb_content = traceback.format_exc()
print(tb_content)
self.stop()
def stop(self):
self._kill.set()
self._thread.join()
KEEP = True
def callback():
global KEEP
KEEP = False
print("ENDED", time.strftime("%M:%S"))
if __name__ == "__main__":
count = 0
t = Timer(timerType=Timer.ONEOFF)
t.start(5000, callback)
print("START", time.strftime("%M:%S"))
while KEEP:
if count % 10000000 == 0:
print("STILL RUNNING")
count += 1
注意 while 循环和 time.sleep() 语句在单独的线程中运行,使用 time.time() 测量经过的时间,并使用回调 function 在时间结束时调用(在您的情况下,此回调function 将用于检查长时间运行的进程是否已完成)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.