[英]How to run parallel processes with multiprocessing terminate one of them from another and then restart
I get error when running the code
TypeError:出于安全原因,不允许腌制 AuthenticationString 对象
我对此很陌生...您可以将自己的全新解决方案/代码添加到与我的代码类似的代码中,只要您能满足目标(例如,无需使用数组来存储进程ID以进行终止等)。 .),目标是: 1.并行运行多个进程,然后在 STATECHECK 中满足某些条件时 2.杀死附加到特定数组的进程(在本例中为 main_processes,normal_processes) 3.然后从另一个进程终止它们(我尝试从 statecheck() 中的 reset() 执行此操作 4.从 statecheck 重新启动相同的进程(randomx)
import multiprocessing
import time
from multiprocessing import Process
data_dict = {'y': 4,
'h': 5,
'j': 6,
'o': 7,
'p': 3,
'b': 11}
def randomx(key):
for i in range(0, 2, 1):
print(key)
time.sleep(data_dict[key])
def move():
print("Starting move2obj")
for i in range(0, 5, 1):
print(i)
def statecheck(np, cp):
print("statecheck started")
reset(np, cp)
time.sleep(10)
randomx()
time.sleep(20)
def run():
for key in data_dict:
key = Process(target=randomx, args=key)
print(main_processes, key)
main_processes.append(key)
all_processes.append(key)
key.start()
process24 = multiprocessing.Process(target=move)
process24.start()
process11 = Process(target=statecheck, args=[normal_processes, main_processes])
process11.start()
normal_processes.append(str(process24))
all_processes.append(str(process24))
all_processes.append(str(process11))
def reset(normal_processes, main_processes, *args):
time.sleep(1)
print("killing normal :", normal_processes)
for process in normal_processes:
process.terminate()
process.join()
time.sleep(1)
print("killing combat :", main_processes)
for process in main_processes:
process.terminate()
process.join()
def processes():
print(main_processes, normal_processes, all_processes)
return normal_processes, main_processes, all_processes
if __name__ == "__main__":
manager = multiprocessing.Manager()
normal_processes = manager.list()
main_processes = manager.list()
all_processes = manager.list()
run()
这是与您的代码相关的更简单的方法来重现您遇到的错误:
import time
from multiprocessing import Manager, Process
def a():
time.sleep(4)
print('done')
if __name__ == "__main__":
manager = Manager()
l = manager.list()
b = Process(target=a)
b.start()
l.append(b)
b.join()
输出
TypeError: Pickling an AuthenticationString object is disallowed for security reasons
发生这种情况的原因已在此答案中进行了解释。 简而言之,您正在尝试腌制一些明确表示不应该腌制的东西。 然而,这并不意味着它无法解决。 您只需要使用multiprocess ,并使进程的authkey
可以选择:
import time
from multiprocess import Manager, Process
class MyProcess(Process):
def _prepare(self):
self._config['authkey'] = bytes(self._config['authkey'])
def start(self):
self._prepare()
return super().start()
def a():
time.sleep(4)
print('done')
if __name__ == "__main__":
manager = Manager()
l = manager.list()
b = MyProcess(target=a)
b.start()
l.append(b)
b.join()
输出
done
因此,对于您的代码,不要使用Process
类,而是使用上面的MyProcess
类来创建可挑选的进程。
话虽如此,除非您知道自己在做什么并意识到可能的后果,否则最好不要尝试解决此类“问题”。 他们在那里,按设计,是有原因的。 因此,您不应创建进程并将它们添加到托管列表(然后将该列表传递给其他进程),而应该只从创建它们的进程中加入/终止进程。
编辑
另外,数据是如何在进程之间传递的? 在您的示例中,您没有演示进程之间的任何数据传输吗? 例如,如果我在 def a 中写入 print(l) 它会返回错误吗?
“演示”数据传输是什么意思? 此外,您正在做的事情显然会引发错误,因为a()
不知道l
是什么。 您需要将托管列表作为参数传递给a
才能正常工作。
现在关于从其他进程终止进程,这是可能的,但我真的想不出使用其他有效方法无法完成的这种事情的用例。 简而言之,如果您按照这些思路进行思考,您可能需要重新评估您的整个方法。
但是,如果您仍然想这样做,您可以通过使用管理器在另一个进程中创建进程,并将这些进程而不是实际进程传递给其他进程来做到这一点。 为此,您不需要multiprocess
进程,也不需要更改进程本身的authkey
。 例子:
import time
from multiprocessing import Manager, Process
from multiprocessing.managers import NamespaceProxy, BaseManager
import inspect
class ObjProxy(NamespaceProxy):
"""Returns a proxy instance for any user defined data-type. The proxy instance will have the namespace and
functions of the data-type (except private/protected callables/attributes). Furthermore, the proxy will be
pickable and can its state can be shared among different processes. """
@classmethod
def populate_obj_attributes(cls, real_cls):
DISALLOWED = set(dir(cls))
ALLOWED = ['__sizeof__', '__eq__', '__ne__', '__le__', '__repr__', '__dict__', '__lt__',
'__gt__']
DISALLOWED.add('__class__')
new_dict = {}
for (attr, value) in inspect.getmembers(real_cls, callable):
if attr not in DISALLOWED or attr in ALLOWED:
new_dict[attr] = cls._proxy_wrap(attr)
return new_dict
@staticmethod
def _proxy_wrap(attr):
""" This method creates function that calls the proxified object's method."""
def f(self, *args, **kwargs):
return self._callmethod(attr, args, kwargs)
return f
attributes = ObjProxy.populate_obj_attributes(Process)
ProcessProxy = type("ProcessProxy", (ObjProxy,), attributes)
def func1():
time.sleep(7)
print('done')
def func2(l):
proc = l[0]
proc.terminate()
print('terminated')
if __name__ == "__main__":
m = Manager()
l = m.list()
BaseManager.register('Process', Process, ProcessProxy, exposed=tuple(dir(ProcessProxy)))
manager = BaseManager()
manager.start()
p1 = manager.Process(target=func1)
p2 = manager.Process(target=func2, args=(l,))
print(p1, p2)
l.append(p1)
p1.start()
p2.start()
p2.join()
p2.join()
输出
<Process name='Process-2:1' parent=115344 initial> <Process name='Process-2:2' parent=115344 initial>
terminated
只需使用manager.Process
而不是Process
类来创建流程。 如果您想了解有关上述管理器和代理如何工作的更多详细信息,请查看此答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.