![](/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.