在 Python 个进程之间共享一个嵌套对象,对 tasklet(协同程序)具有写访问权限?

Sharing a nested object between Python processes with write access for tasklets(coroutines)?

如何在 Python 个进程之间共享一个嵌套对象,对 tasklet(协程)具有写入权限?

这是一个简化的示例,其中包含我为正确提出这个问题而写的类比;

首先请安装 greenlet 软件包:sudo pip install greenlet

在下面的例子中:

greentest.py:

import random
from greenlet import greenlet

global_counter = 0

class Animal():

    def __init__(self,nature):
        self.limbs = 0
        nature.animals.append(self)
        self.tasklet = greenlet(self.live)

    def live(self,nature):
        global global_counter
        while True:
            self.limbs = random.randint(1, 10)
            global_counter += 1
            if global_counter > 1000:
                break
            random.sample(nature.animals,1)[0].tasklet.switch(nature)

class Nature():

    def __init__(self,how_many):
        self.animals = []
        for i in range(how_many):
            Animal(self)
        print str(how_many) + " animals created."
        self.animals[0].live(self)

结果是:

>>> import greentest
>>> habitat = greentest.Nature(8)
8 animals created.
>>> habitat.animals[0].limbs
3
>>> greentest.global_counter
1002

按预期工作。更改 limbsglobal_counter 的值(非零)

但是当我将 multiprocessing 添加到等式时;

greentest2.py:

import random
import multiprocessing
from greenlet import greenlet

global_counter = 0

class Animal():

    def __init__(self,nature):
        self.limbs = 0
        nature.animals.append(self)
        self.tasklet = greenlet(self.live)

    def live(self,nature):
        global global_counter
        while True:
            self.limbs = random.randint(1, 10)
            global_counter += 1
            if global_counter > 1000:
                break
            random.sample(nature.animals,1)[0].tasklet.switch(nature)

class Nature():

    def __init__(self,how_many):
        self.animals = []
        for i in range(how_many):
            Animal(self)
        print str(how_many) + " animals created."
        #self.animals[0].live(self)
        jobs = []
        for i in range(2):
            p = multiprocessing.Process(target=self.animals[0].live, args=(self,))
            jobs.append(p)
            p.start()

结果与预期不符:

>>> import greentest2
>>> habitat = greentest2.Nature(8)
8 animals created.
>>> habitat.animals[0].limbs
0
>>> greentest2.global_counter
0

limbsglobal_counter 的值都没有改变(零)。我认为这是因为进程之间不共享 Animal class 和 global_counter 的实例。那么如何在进程之间共享 Nature class 的这个实例或 Animal class 的这些实例?

ADDITION 根据@noxdafox 的回答;

greentest3.py:

import random
import multiprocessing
from greenlet import greenlet

global_counter = multiprocessing.Value('i', 0)

class Animal():

    def __init__(self,nature):
        self.limbs = 0
        nature.animals.append(self)
        self.tasklet = greenlet(self.live)

    def live(self,nature):
        global global_counter
        while True:
            self.limbs = random.randint(1, 10)
            global_counter.value += 1
            if global_counter.value > 1000:
                break
            random.sample(nature.animals,1)[0].tasklet.switch(nature)

class Nature():

    def __init__(self,how_many):
        self.animals = []
        for i in range(how_many):
            Animal(self)
        print str(how_many) + " animals created."
        #self.animals[0].live(self)
        jobs = []
        for i in range(2):
            p = multiprocessing.Process(target=self.animals[0].live, args=(self,))
            jobs.append(p)
            p.start()

然后结果是:

>>> import greentest3
>>> habitat = greentest3.Nature(8)
8 animals created.
>>> habitat.animals[0].limbs
0
>>> greentest3.global_counter.value
1004

我完全知道 global_counter 可以与此方法共享,因为它是一个 整数 但我实际上是在问如何共享 [=19 的实例=] 和 Animal class 在进程之间。

不同进程不共享内存。

如果你需要共享的是单个变量,你可能可以使用multiprocessing.Value

import multiprocessing

def function(counter):
    counter.value += 1

counter = multiprocessing.Value('i')
p = multiprocessing.Process(target=function, args=(counter))
p.start()
p.join()

编辑:根据更新回答。

没有允许在内存中共享整个对象的抽象机制。共享内存通常实现为一个简单的数组,其中进程可以 read/write 一旦获得资源。

此外,OOP 和 threading/multiprocessing 不能很好地结合在一起。恕我直言,应将其视为反模式。在复杂对象之上,您可以添加对其属性的并发访问和修改。这是漫长而乏味的调试会话的单程票。

推荐的模式是使用消息队列。将线程和进程想象成通过特定通道进行通信的独立实体可以显着简化问题。