Python多处理—在父类和派生类之间共享的多处理数组中操作数据的问题

Python多处理—在父类和派生类之间共享的多处理数组中操作数据的问题,python,multiprocessing,Python,Multiprocessing,我想实现一种在父函数和它将生成的类的实例之间共享信息表的方法。根据我读到的,我需要使用一个给定长度的ctypes.c\u char\u p表 我已设法从父函数初始化该表,然后将其传递给被调用的类。从类的\uuuu init\uuuu()中,我可以访问它的内容。最后,我尝试操作它们(在本例中颠倒名称),我从类中确认共享数组按预期填充,但当我尝试查看父进程的内容时,我得到了垃圾 我的代码和输出如下: 代码: #/usr/bin/env蟒蛇3 导入多处理 导入ctypes 随机输入 导入json 类别

我想实现一种在父函数和它将生成的类的实例之间共享信息表的方法。根据我读到的,我需要使用一个给定长度的
ctypes.c\u char\u p

我已设法从父函数初始化该表,然后将其传递给被调用的类。从类的
\uuuu init\uuuu()
中,我可以访问它的内容。最后,我尝试操作它们(在本例中颠倒名称),我从类中确认共享数组按预期填充,但当我尝试查看父进程的内容时,我得到了垃圾

我的代码和输出如下:

代码:
#/usr/bin/env蟒蛇3
导入多处理
导入ctypes
随机输入
导入json
类别employee(multiprocessing.Process):
定义初始化(自我、员工数据、共享数组字段):
self.employee_data=员工_数据
self.shared\u array\u fields=共享\u array\u fields
#self.lock=lock
打印(“***”*100)
打印(“在类:\n中,员工数据[:])
self.run()
def运行(自):
对于范围内的ii(自共享数组字段):
employee_string=self.employee_数据[ii]。解码(“utf-8”)
new_name_json=json.loads(employee_字符串)
new_name=new_name_json[“name”][::-1]
self.employee_data[ii]=字节(“{”名称“:“'+str(新_名称)+'“}',“utf-8”)
打印(“***”*100)
打印(“操作后在课堂上:\n”,self.employee_数据[:])
共享_数组_字段=5
def main():
全局共享数组字段
lock=multiprocessing.lock()
employee\u data=multiprocessing.Array(ctypes.c\u char\p,共享\u数组\u字段)
对于范围内的ii(共享数组字段):
name=''.join(random.choice(['a'、'b'、'c'、'd'、'e'])表示范围(10)内的i)+“u”+str(ii)
employee_data[ii]=字节('{“name”:“'+str(name)+'“}',“utf-8”)
打印(“***”*100)
打印(“课前:\n”,员工数据[:])
proc1=多处理.Process(目标=员工,参数=(员工\数据,共享\数组\字段))
proc1.start()
proc1.join()
#时间。睡眠(1)
打印(“***”*100)
打印(“课后:\n”,员工数据[:])
如果名称=“\uuuuu main\uuuuuuuu”:
main()
结果:
非常感谢您的帮助。

使用数组非常麻烦,因为很难为它重写一个全新的值。还有,为什么需要将字典转换为字符串,然后再转换回使用数组呢?最后,您希望在进程之间共享的任何结构都应该由调用
multiprocessing.manager()
创建的“管理器”实例创建,除非您想自己管理同步

实现目标的最简单方法是让管理器创建两个队列对象,一个输入队列(用于流程的输入)和一个输出队列来保存结果。在这种特殊情况下,您可以对这两个对象使用相同的队列对象,但这更干净,通常是当多个输入和输出由一个进程池同时处理,而不是使用标准库模块(如
multiprocessing.pool
concurrent.futures
)时使用的

最后,构建
进程
子类需要一些调整(构造函数需要调用基类构造函数,而不应该调用
运行
)。用大写字母命名你的类也是很常见的,尽管我没有改变名字。我还认为更常见的做法是不将
过程子类化。通常,只需编写一个函数并传递给调用
进程
目标
args
和/或
kwargs
参数

更新以使用托管词典

#!/usr/bin/env python3

import multiprocessing
import random

class employee(multiprocessing.Process):

    def __init__(self, employees):

        super().__init__()   # init the base class !!!
        self.employees = employees

        print("**" * 100)
        print("IN class:\n", self.employees[:])


    def run(self):
        employees = self.employees
        for i, employee in enumerate(employees):
            new_name = employee["name"][::-1]
            employee["name"] = new_name
            employees[i] = employee # must be rewritten to show it has changed. Yuck!
        #self.employees = employees

        print("**" * 100)
        print("IN class AFTER manipulation:\n", employees[:])


def main():

    manager = multiprocessing.Manager()
    employees = manager.list()

    for ii in range(5):
        name = ''.join(random.choice(['a', 'b', 'c', 'd', 'e']) for i in range(10)) + "_" + str(ii)
        employees.append({"name": name})

    print("**" * 100)
    print("BEFORE class:\n", employees[:])

    proc1 = employee(employees)
    proc1.start()
    proc1.join()

    # time.sleep(1)

    print("**" * 100)
    print("AFTER class:\n", employees[:])


if __name__ == "__main__":
    main()

非常感谢所有的建议,我试图避免使用队列,因为它比在父进程和多个子进程之间共享一个结构化数组更复杂,但由于我完全陷入困境,我将尝试使用队列。我会在工作结束后玩一玩并恢复。我相信队列大大简化了解决方案。好吧,我认为一个数组,每个衍生进程将修改其自己的必要信息字典,并且该数组将自动实时反映到父进程和其他子进程,这将比有两个队列更容易(每个子进程)您需要不断轮询新消息,但由于我不知道我做错了什么(我找到的所有示例都是将函数派生为进程,而不是整个类),我将尝试您的方法。首先,初始化(Unicode)数组的最简单方法字符是
employee\u data=multiprocessing.Array('u','{“name”:“John Doe”}')
,完全没有字节。但更新仍然是一个问题。在简单的人工情况下,您正在反转名称,因此既不缩短也不延长响应,因此可以就地更新字符(你仍然需要一个字符一个字符地做)。但是如果结果更短或更长呢?尝试通过更新输入来提供响应是一种糟糕的方法。我已经用我认为你会喜欢的东西更新了答案,那就是使用管理列表(如果多个进程同时访问它,则不需要显式锁定)而不是
multiprocessing.Array
,该数组用于保存(词典)列表的JSON表示。
#!/usr/bin/env python3

import multiprocessing
import random

class employee(multiprocessing.Process):

    def __init__(self, employees):

        super().__init__()   # init the base class !!!
        self.employees = employees

        print("**" * 100)
        print("IN class:\n", self.employees[:])


    def run(self):
        employees = self.employees
        for i, employee in enumerate(employees):
            new_name = employee["name"][::-1]
            employee["name"] = new_name
            employees[i] = employee # must be rewritten to show it has changed. Yuck!
        #self.employees = employees

        print("**" * 100)
        print("IN class AFTER manipulation:\n", employees[:])


def main():

    manager = multiprocessing.Manager()
    employees = manager.list()

    for ii in range(5):
        name = ''.join(random.choice(['a', 'b', 'c', 'd', 'e']) for i in range(10)) + "_" + str(ii)
        employees.append({"name": name})

    print("**" * 100)
    print("BEFORE class:\n", employees[:])

    proc1 = employee(employees)
    proc1.start()
    proc1.join()

    # time.sleep(1)

    print("**" * 100)
    print("AFTER class:\n", employees[:])


if __name__ == "__main__":
    main()