假设您有两个用manager.list((创建的列表和两个用manager创建的锁。锁定((。如何将每个锁分配给每个列表?我做得像
lock1 = manager.Lock()
lock2 = manager.Lock()
list1 = manager.list()
list2 = manager.list()
当我想从列表中写入/读取时
lock1.acquire()
list1.pop(0)
lock1.release()
lock2.acquire()
list2.pop(0)
lock2.released()
今天我意识到没有什么能把lock1和list1联系起来。我是不是误解了这些功能?
TL;DR是的,这可能是XY问题!
如果您创建一个multiprocessing.Manager()
并使用其方法创建容器基元(.list
和.dict
(,它们将已经同步,您不需要自己处理同步基元
from multiprocessing import Manager, Process, freeze_support
def my_function(d, lst):
lst.append([x**2 for x in d.values()])
def main():
with Manager() as manager: # context-managed SyncManager
normal_dict = {'a': 1, 'b': 2}
managed_synchronized_dict = manager.dict(normal_dict)
managed_synchronized_list = manager.list() # used to store results
p = Process(
target=my_function,
args=(managed_synchronized_dict, managed_synchronized_list)
)
p.start()
p.join()
print(managed_synchronized_list)
if __name__ == '__main__':
freeze_support()
main()
% python3 ./test_so_66603485.py
[[1, 4]]
多处理。阵列,也是同步
BEWARE:代理对象不能直接与它们的Python集合等价物进行比较
注意:多处理中的代理类型不支持按值进行比较。例如,我们有:
>>> manager.list([1,2,3]) == [1,2,3] False
在进行比较时,应该只使用引用对象的副本。
一些混淆可能来自同步原语的多处理文档部分,这意味着应该使用管理器来创建同步原语,而实际上管理器已经可以为进行同步
同步原语
通常,同步原语在多进程程序中不像在多线程程序中那样必要。请参阅有关线程模块的文档。
请注意,还可以通过使用管理器对象来创建同步原语——请参见管理器。
如果你只使用multiprocessing.Manager()
,根据文档,它是
返回一个已启动的SyncManager对象,该对象可用于在进程之间共享对象。返回的管理器对象对应于派生的子进程,并具有创建共享对象并返回相应代理的方法。
来自SyncManager部分
它的方法为许多常用的数据类型创建并返回代理对象,以便在进程之间同步。其中包括共享列表和词典。
这意味着你可能已经拥有了你想要的大部分
- 具有用于构建托管类型的方法的管理器对象
- 通过代理对象进行同步
最后,从专门关于锁定对象实例的注释中总结线程
- 没有固有的方法来判断某个命名锁是用于除元信息(如名称、注释、文档(之外的任何特定内容。。相反,它们可以自由用于您可能需要的任何同步
- 可以制作一些有用的类/容器来管理锁和它应该同步的任何东西——一个普通的
multiprocessing.Manager
(SyncManager
(的.list
和.dict
可以做到这一点,还有各种其他有用的构造,如管道和队列 - 一个锁可以用于同步任何数量的操作,但拥有更多的锁可能是一种有价值的权衡,因为它们可能会不必要地阻止对资源的访问
- 还存在用于不同目的的各种同步原语
value = my_queue.get() # already synchronized
if not my_lock1.acquire(timeout=5): # False if cannot acquire
raise CustomException("failed to acquire my_lock1 after 5 seconds")
try:
with my_lock2(): # blocks until acquired
some_shared_mutable = some_container_of_mutables[-1]
some_shared_mutable = some_object_with_mutables.get()
if foo(value, some_shared_mutable):
action1(value, some_shared_mutable)
action2(value, some_other_shared_mutable)
finally:
lock2.release()