在 Python 个进程之间共享一个嵌套对象,对 tasklet(协同程序)具有写访问权限?
Sharing a nested object between Python processes with write access for tasklets(coroutines)?
如何在 Python 个进程之间共享一个嵌套对象,对 tasklet(协程)具有写入权限?
这是一个简化的示例,其中包含我为正确提出这个问题而写的类比;
首先请安装 greenlet
软件包:sudo pip install greenlet
在下面的例子中:
Nature
class 的实例被 habitat
变量引用
- 这个
Nature
class 的实例有一个名为 animals
的实例变量
- 在启动
Nature
class 的实例时,创建了 8 个不同的 Animal
class 实例并将其附加到 animals
实例变量。现在,如果我是正确的,Nature
的这个实例是一个嵌套对象。
- 作为最后一步
live
个 Animal
个实例的实例函数,使用 greenlet
包的 switch()
函数随机切换,直到 global_counter
达到 1000。此 live
函数随机改变Animal
个实例的limbs
个实例变量的值。
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
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 不能很好地结合在一起。恕我直言,应将其视为反模式。在复杂对象之上,您可以添加对其属性的并发访问和修改。这是漫长而乏味的调试会话的单程票。
推荐的模式是使用消息队列。将线程和进程想象成通过特定通道进行通信的独立实体可以显着简化问题。
如何在 Python 个进程之间共享一个嵌套对象,对 tasklet(协程)具有写入权限?
这是一个简化的示例,其中包含我为正确提出这个问题而写的类比;
首先请安装 greenlet
软件包:sudo pip install greenlet
在下面的例子中:
Nature
class 的实例被habitat
变量引用- 这个
Nature
class 的实例有一个名为animals
的实例变量
- 在启动
Nature
class 的实例时,创建了 8 个不同的Animal
class 实例并将其附加到animals
实例变量。现在,如果我是正确的,Nature
的这个实例是一个嵌套对象。 - 作为最后一步
live
个Animal
个实例的实例函数,使用greenlet
包的switch()
函数随机切换,直到global_counter
达到 1000。此live
函数随机改变Animal
个实例的limbs
个实例变量的值。
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
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 不能很好地结合在一起。恕我直言,应将其视为反模式。在复杂对象之上,您可以添加对其属性的并发访问和修改。这是漫长而乏味的调试会话的单程票。
推荐的模式是使用消息队列。将线程和进程想象成通过特定通道进行通信的独立实体可以显着简化问题。