python - 跨多个进程和模块共享的全局可修改对象
问题描述
问题
我正在编写一个软件,我想在其中共享某个模块的对象。这个对象应该可以从不同的模块和不同的进程中修改。考虑以下(简化)版本的问题:
模块
module_shared.py
# Example class with simplified behaviour
class Shared:
def __init__(self):
self.shared = dict()
def set(self, **kwargs):
for key, value in kwargs.items():
self.shared[key] = value
def get(self, *args):
return {key: self.shared[key] for key in args} if args else self.shared
# Module-scope instance of the Shared class
shared = Shared()
module_a.py
from multiprocessing import Process
from time import sleep
import module_shared as ms
def run():
Process(target=run_process).start()
def run_process():
i = 0
while True:
sleep(3)
ms.shared.set(module_a=i)
i+=1
print("Shared from within module_a", ms.shared.get())
module_b.py
from multiprocessing import Process
from time import sleep
import module_shared as ms
def run():
Process(target=run_process).start()
def run_process():
i = 0
while True:
sleep(2)
ms.shared.set(module_b=i)
i-=1
print("Shared from within module_b", ms.shared.get())
module_main.py
import module_a
import module_b
import module_shared as ms
from time import sleep
if __name__ == '__main__':
module_a.run()
module_b.run()
while True:
sleep(5)
print("Shared from within module_main", ms.shared.get())
输出
运行的输出module_main
如下:
Shared from within module_b {'module_b': 0}
Shared from within module_a {'module_a': 0}
Shared from within module_b {'module_b': -1}
Shared from within module_main {}
Shared from within module_a {'module_a': 1}
Shared from within module_b {'module_b': -2}
...
预期输出如下:
Shared from within module_b {'module_b': 0}
Shared from within module_a {'module_a': 0, 'module_b': 0}
Shared from within module_b {'module_a': 0, 'module_b': -1}
Shared from within module_main {'module_a': 0, 'module_b': -1}
Shared from within module_a {'module_a': 1, 'module_b': -1}
Shared from within module_b {'module_a': 1, 'module_b': -2}
...
进一步说明
实例不会被全局修改,shared
因为每个进程都有自己的内存空间。最初我尝试使用Manager
frommultiprocessing
模块修复它,但是,我未能设置它,我认为是由于导入语句的执行时间和方式出现错误。这是调用's时Manager()
的错误消息:Shared
__init__
RuntimeError:
An attempt has been made to start a new process before the
current process has finished its bootstrapping phase.
This probably means that you are not using fork to start your
child processes and you have forgotten to use the proper idiom
in the main module:
if __name__ == '__main__':
freeze_support()
...
The "freeze_support()" line can be omitted if the program
is not going to be frozen to produce an executable.
目前最好的解决方案是使用线程,但是我更喜欢使用进程。当然,如果存在任何更简单(或更好)的解决方案,我会很乐意考虑它们。
编辑:
我意识到我在之前的线程尝试中犯了一个错字,并且使用多个线程实际上工作得很好。学习阅读你的代码两次的一个很好的教训......
解决方案
一种方法是使用各种缓存模块之一。diskcache
,shelve
等都提供持久化对象的能力。当然,pickle
。
例如,使用diskcache库,您可以采用这种方法,将您的替换module_shared.py
为:
### DISKCACHE Example ###
from diskcache import Cache
cache = Cache('test_cache.cache')
# Example class with simplified behaviour
class Shared:
def __init__(self, cache):
self.cache = cache
self.cache.clear()
def set(self, **kwargs):
for key, value in kwargs.items():
cache.set(key, value)
def get(self, *args):
return {key: cache.get(key) for key in args} if args else {(key, cache.get(key)) for key in cache.iterkeys()}
# Module-scope instance of the Shared class
shared = Shared(cache)
输出:
Shared from within module_b {('module_b', 0)}
Shared from within module_a {('module_a', 0), ('module_b', 0)}
Shared from within module_b {('module_a', 0), ('module_b', -1)}
Shared from within module_main {('module_a', 0), ('module_b', -1)}
Shared from within module_a {('module_b', -1), ('module_a', 1)}
Shared from within module_b {('module_b', -2), ('module_a', 1)}
在上面的示例中,module_shared.py
是唯一更改的文件。
各种持久性库/方法中的每一个都有自己的怪癖和功能。如果您绝对需要将整个类实例对象持久化,那就在那里。:) 性能仅取决于您对缓存机制的实施和选择。diskcache
已经证明对我很有能力。
我在diskcache
这里实现了非常简单的功能来演示功能。请务必阅读清晰简洁的文档,以便更好地理解。
另外,我的输出是一个无序的字典。您可以轻松地产生排序以module_a
始终首先匹配您自己的输出。为简单起见,我省略了这一点。
推荐阅读
- java - 使用 Volley 从服务器获取数据时面临空指针异常
- python - 文件存在但仍然出现 FileNotFoundError
- linux - 获取失败....哈希和不匹配
- javascript - 正则表达式返回空字符空间和未定义?
- python - 递归删除所有相邻的重复项。对于不同的输入,我得到相同的输出
- java - 在更新现有表 firebase 时创建新表
- bash - Bash:条件表达式和(伪)布尔变量的最佳实践语法是什么
- r - 在 R 数据框中的所有单元格中复制/拖动地址
- flutter - 如何在 Flutter 上为 showGeneralDialog 添加灵活高度?
- vb.net - VB.NET 到处共享字符串列表