【问题标题】:Shared array of objects using multiprocessing in python在python中使用多处理共享对象数组
【发布时间】:2014-11-06 20:49:35
【问题描述】:

我正在尝试在 python 程序的不同进程之间创建一个共享对象数组(类的实例)。这些对象中的每一个都将在程序中进行修改。为此,我使用如下多重处理:

import multiprocessing
import numpy as np
sh = multiprocessing.RawArray (ctypes.py_object, 10)
f = np.frombuffer(sh, dtype=object)

我得到的错误是:

Traceback (most recent call last):
  File "<pyshell#14>", line 1, in <module>
    f = np.frombuffer(sh, dtype=object)
ValueError: cannot create an OBJECT array from memory buffer

现在我的问题是,首先,这通常是解决这个问题的正确方法,其次,我在上述代码中的错误是什么?提前谢谢你。

【问题讨论】:

    标签: python python-2.7 multiprocessing


    【解决方案1】:

    ctypes.py_object 代表 C 中的 PyObject *。它是指向代表 Python 对象的 struct 的指针,驻留在进程的私有内存中,并包含更多指针。另一个进程无法访问它;试图在进程之间共享指针是没有用的。

    另见this answer by Alex Martelli

    【讨论】:

    • 实际上,使用Array和RawArray(在多进程中)是一种在内存中创建共享数组以供多个进程访问的方法。我可以为共享整数数组编写上面的代码,但在为对象数组编写它时遇到问题。例如,如果我写: >>> import multiprocessing as mp >>> import numpy as np >>> sh = mp.RawArray (ctypes.c_int , 10) >>> f = np.frombuffer(sh, dtype=int) >>> f[0]=1 >>> sh[0] 1 完美运行!
    • @user823743 正确,但你不能对指针做同样的事情。
    • 你是对的;幸运的是,我找到了另一种避免多处理的方法。谢谢。
    【解决方案2】:

    您可能想要使用multiprocessing.Queue,您可以在其中转储对象而无需担心类型。它也是线程安全和进程安全的。

    这是一个简单的队列示例,用于解决生产者-消费者问题(original source,比萨饼是我的小礼物)。

    from multiprocessing import Process, Queue
    
    class Pizza(object):
        def __init__(self, pizza_num):
            self.pizza_num = pizza_num
            self.num_slices = 8
    
    sentinel = "NO PIZZA"
    
    def producer(initial_num_pizzas, total_num_pizzas, q):
        """Cooks Pizzas to be consumed and waits for the consumer to finish eating."""
        print("Producer: I am cooking %s Pizzas and putting them on the Queue!"%(total_num_pizzas-initial_num_pizzas))
        for i in range(q.qsize(), total_num_pizzas):
            print("Producer: Behold, for I have cooked Pizza no. %s"%i)
            q.put(Pizza(i))
        q.put(sentinel)
    
    def consumer(q):
        """Consumes some Pizza. In this case, all it does is set the number of slices to 0."""
        while True:
            pizza = q.get()
            pizza.num_slices = 0
            if pizza == sentinel:
                break
            print("Comsumer: Pizza no. %s was found! It has %s slices, yum!"%(pizza.pizza_num, pizza.num_slices))
    
    if __name__ == '__main__':
        q = Queue()
        total_num_pizzas = 10
        initial_num_pizzas = 4
        ## Let's add some Pizzas beforehand:
        for i in range(0, initial_num_pizzas):
            q.put(Pizza(i))
        print("Main: I have precooked %s Pizzas."%q.qsize())
    
        producer_proc = Process(target=producer, args=(initial_num_pizzas, total_num_pizzas, q))
        consumer_proc = Process(target=consumer, args=(q,))
        producer_proc.start()
        consumer_proc.start()
    
        q.close()  ## Shop is closed, no more Pizzas will be added to Queue!
        q.join_thread()
    
        producer_proc.join()
        consumer_proc.join()
    

    下面是一个示例输出。如果您运行它,生产者和消费者打印语句可能会因并行进程的不确定性执行而不同地交错。

    Main: I have precooked 4 Pizzas.
    Producer: I am cooking 6 Pizzas and putting them on the Queue!
    Producer: Behold, for I have cooked Pizza no. 4
    Producer: Behold, for I have cooked Pizza no. 5
    Producer: Behold, for I have cooked Pizza no. 6
    Producer: Behold, for I have cooked Pizza no. 7
    Comsumer: Pizza no. 0 was found! It has 8 slices, yum!
    Comsumer: Pizza no. 1 was found! It has 8 slices, yum!
    Producer: Behold, for I have cooked Pizza no. 8
    Comsumer: Pizza no. 2 was found! It has 8 slices, yum!
    Producer: Behold, for I have cooked Pizza no. 9
    Comsumer: Pizza no. 3 was found! It has 8 slices, yum!
    Comsumer: Pizza no. 4 was found! It has 8 slices, yum!
    Comsumer: Pizza no. 5 was found! It has 8 slices, yum!
    Comsumer: Pizza no. 6 was found! It has 8 slices, yum!
    Comsumer: Pizza no. 7 was found! It has 8 slices, yum!
    Comsumer: Pizza no. 8 was found! It has 8 slices, yum!
    Comsumer: Pizza no. 9 was found! It has 8 slices, yum!
    

    请注意,您应该use Sentinels to mark the end of your Queue。我在这里使用了“NO PIZZA”,但它们可以是任何东西。

    【讨论】:

      猜你喜欢
      • 2020-11-13
      • 1970-01-01
      • 2019-10-09
      • 2023-03-10
      • 2017-02-07
      • 2023-04-03
      • 1970-01-01
      • 2021-03-19
      • 2022-10-13
      相关资源
      最近更新 更多