繁体   English   中英

如何使用多处理运行并行进程从另一个终止其中一个然后重新启动

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM