如何在具有Tasklet(协程)的写访问权限的Python进程之间共享嵌套对象?
这是一个简化的示例,上面有一个类似的例子,正是我为正确回答这个问题而写的。
首先,请使用以下命令安装greenlet
软件包:sudo pip install greenlet
在下面的示例中:
Nature
引用的类的实例habitat
Nature
类的实例有一个实例变量,称为animals
Nature
该类实例的同时,Animal
创建了8个不同的类实例并将其附加到animals
实例变量。现在,如果我是对的,Nature
则该实例是一个嵌套对象。live
实例的实例函数Animal
将使用greenlet
程序包的switch()
函数进行随机切换,直到global_counter
达到1000。此live
函数将随机更改limbs
实例的实例变量的值Animal
。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
正常工作。改变的值limbs
和global_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
两者的值limbs
和global_counter
不变(零)。我认为这是因为Animal
类的实例global_counter
并不在进程之间共享。那么,如何在进程之间共享Nature
该类实例或这些Animal
类实例呢?
加成根据@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
可以使用此方法共享,因为它是整数,但是我实际上是在问如何在进程之间共享Nature
和Animal
类的实例。
不同的进程不共享它们的内存。
如果您需要共享的是单个变量,则可以使用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()
编辑:根据更新答复。
没有抽象机制允许共享内存中的整个对象。共享内存通常被实现为一个简单的数组,一旦获取资源,进程就可以在其中进行读/写操作。
而且,OOP和线程/多处理不能很好地融合在一起。恕我直言,应被视为反模式。在复杂对象之上,您可以添加并发访问和修改其属性。这是进行冗长乏味的调试会话的一种方式。
推荐的模式是使用消息队列。将线程和进程想象成孤立的实体,可以通过特定的渠道进行通信,从而大大简化了问题。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句