已经有很多关于在 Python 中创建守护进程的问题,比如这个,它很好地回答了这部分。
那么,你如何让你的守护进程做后台工作呢?
正如您所怀疑的,线程是一个明显的答案。但存在三种可能的复杂性。
首先,有关机。如果幸运的话,您的crunchData
函数可以随时被立即终止,而不会损坏数据或(太重要)丢失工作。在这种情况下:
def worker():
while True:
crunchData()
# ... somewhere in the daemon startup code ...
t = threading.Thread(target=worker)
t.daemon = True
t.start()
请注意t.daemon
. “守护线程”与您的程序是守护进程无关;这意味着您可以退出主进程,它会被立即杀死。
但如果crunchData
不能被杀死呢?然后你需要做这样的事情:
quitflag = False
quitlock = threading.Lock()
def worker():
while True:
with quitlock:
if quitflag:
return
crunchData()
# ... somewhere in the daemon startup code ...
t = threading.Thread(target=worker)
t.start()
# ... somewhere in the daemon shutdown code ...
with quitlock:
quitflag = True
t.join()
我假设每次迭代crunchData
都不会花费那么长时间。如果是这样,您可能需要quitFlag
在函数本身内定期检查。
同时,您希望您的请求处理程序访问后台线程正在生成的一些数据。您还需要在那里进行某种同步。
显而易见的是只使用另一个Lock
. 但是很有可能crunchData
经常写入其数据。如果它一次持有锁 10 秒,请求处理程序可能会阻塞 10 秒。但如果它获取并释放锁一百万次,那可能需要比实际工作更长的时间。
一种替代方法是对您的数据进行双重缓冲:crunchData
写入一个新副本,然后在完成后,短暂地抓住锁并设置currentData = newData
.
根据您的用例,a Queue
、文件或其他内容可能更简单。
最后,crunchData
大概是做了大量的CPU工作。您需要确保请求处理程序只做很少的 CPU 工作,否则每个请求都会使事情变慢,因为两个线程争夺 GIL。通常这没有问题。如果是,请使用 amultiprocessing.Process
而不是 a Thread
(这使得在两个进程之间共享或传递数据稍微复杂一些,但仍然不算太糟糕)。