我有兩個 python 腳本,我希望它們相互通信。具體來說,如果后者需要,我希望腳本Communication.py向腳本Process.py發送一個陣列。我使用了模塊multiprocessing.Process并multiprocessing.Pipe使其作業。我的代碼有效,但我想優雅地處理 SIGINT 和 SIGTERM,我嘗試了以下方法,但它沒有優雅地退出:
行程.py
from multiprocessing import Process, Pipe
from Communication import arraySender
import time
import signal
class GracefulKiller:
kill_now = False
def __init__(self):
signal.signal(signal.SIGINT, self.exit_gracefully)
signal.signal(signal.SIGTERM, self.exit_gracefully)
def exit_gracefully(self, *args):
self.kill_now = True
def main():
parent_conn, child_conn = Pipe()
p = Process(target=arraySender, args=(child_conn,True))
p.start()
print(parent_conn.recv())
if __name__ == '__main__':
killer = GracefulKiller()
while not killer.kill_now:
main()
通訊.py
import numpy
from multiprocessing import Process, Pipe
def arraySender(child_conn, sendData):
if sendData:
child_conn.send(numpy.random.randint(0, high=10, size=15, dtype=int))
child_conn.close()
我究竟做錯了什么?
uj5u.com熱心網友回復:
我強烈懷疑您是在 Windows 下運行它,因為我認為您擁有的代碼應該在 Linux 下運行。這就是為什么始終使用您所在的實際平臺標記有關 Python 和多處理的問題很重要的原因。
問題似乎是由于除了您的主行程之外,您還在函式main中創建了一個子行程,該子行程也接收信號。解決方案通常是signal.signal(signal.SIGINT, signal.SIG_IGN)向您的array_sender作業函式添加呼叫。但是這樣做有兩個問題:
- 存在競爭條件:子行程可能在更改忽略信號之前接收到信號。
- 無論如何,在您使用時忽略信號的呼叫
multiprocess.Processing似乎不起作用(也許該類執行自己的信號處理來覆寫這些呼叫)。
解決方案是創建一個多處理池并初始化每個池行程,以便它們在您提交任何任務之前忽略信號。使用池的另一個優點是,盡管在這種情況下我們只需要池大小為 1,因為您一次不會運行多個任務,但您只需要創建一次可以重用的行程。
GracefulKiller順便說一句,通過將類屬性與執行時創建kill_now的實體屬性混合,您的類中存在一些不一致。因此,當主行程正在測驗時,它會訪問類屬性,直到設定為 True 時才會訪問實體屬性。kill_nowself.kill_now = Truekiller.kill_nowself.kill_now
from multiprocessing import Pool, Pipe
import time
import signal
import numpy
class GracefulKiller:
def __init__(self):
self.kill_now = False # Instance attribute
signal.signal(signal.SIGINT, self.exit_gracefully)
signal.signal(signal.SIGTERM, self.exit_gracefully)
def exit_gracefully(self, *args):
self.kill_now = True
def init_pool_processes():
signal.signal(signal.SIGINT, signal.SIG_IGN)
signal.signal(signal.SIGTERM, signal.SIG_IGN)
def arraySender(sendData):
if sendData:
return numpy.random.randint(0, high=10, size=15, dtype=int)
def main(pool):
result = pool.apply(arraySender, args=(True,))
print(result)
if __name__ == '__main__':
# Create pool with only 1 process:
pool = Pool(1, initializer=init_pool_processes)
killer = GracefulKiller()
while not killer.kill_now:
main(pool)
pool.close()
pool.join()
理想情況下 GracefulKiller應該是一個單例類,這樣無論行程實體化多少次,對于要處理的每種型別的信號GracefulKiller,您都只會呼叫一次:signal.signal
class Singleton(type):
def __init__(self, *args, **kwargs):
self.__instance = None
super().__init__(*args, **kwargs)
def __call__(self, *args, **kwargs):
if self.__instance is None:
self.__instance = super().__call__(*args, **kwargs)
return self.__instance
class GracefulKiller(metaclass=Singleton):
def __init__(self):
self.kill_now = False # Instance attribute
signal.signal(signal.SIGINT, self.exit_gracefully)
signal.signal(signal.SIGTERM, self.exit_gracefully)
def exit_gracefully(self, *args):
self.kill_now = True
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/513391.html
