Python 中 SharedMemoryManager 管理的可变数量的 SharedMemory 对象

问题描述 投票:0回答:1

我希望有可变数量的

SharedMemory
对象(取决于我的生产者-消费者应用程序架构中的消费者进程的数量)由
SharedMemoryManager
管理,所以我正在创建
SharedMemory
for 循环中管理器“范围”中的对象。不幸的是,只有最后创建的共享内存才能通过其名称进行访问,之前的共享内存可能会以某种方式被破坏。

此代码产生所描述的行为。我正在使用 Python 3.10。

from multiprocessing.managers import SharedMemoryManager
from multiprocessing.shared_memory import SharedMemory

consumer_process_count = 3

with SharedMemoryManager() as memory_manager:
    memory_names = []
    for i in range(consumer_process_count):
        shared_memory = memory_manager.SharedMemory(size=1)
        memory_names.append(shared_memory.name)
        print(f"Memory {shared_memory.name} created.")

    for memory_name in memory_names:
        try:
            SharedMemory(name=memory_name)
        except FileNotFoundError:
            print(f"Memory {memory_name} not found.")
        else:
            print(f"Memory {memory_name} found.")

我做错了什么,还是无法使用

SharedMemoryManager
来管理可变数量的
SharedMemory
对象?

我有一个不使用

SharedMemoryManager
的解决方案,但我想让我的代码更干净,并利用上下文管理器在出现意外错误时负责资源清理的优势。

python multiprocessing shared-memory producer-consumer
1个回答
0
投票

在我看来,当您继续执行

shared_memory = memory_manager.SharedMemory(size=1)
的循环时,您正在用新值覆盖
shared_memory
的前一个值,并且由于不再有任何对先前共享内存的引用,因此它正在被垃圾收集。我怀疑您能够找到按名称分配的最后一个共享内存块。

解决方案是保留对所有分配的共享内存块的引用。例如,将共享内存块引用附加到列表中,

shared_memories
从而防止该块被垃圾收集:

if __name__ == '__main__':
    from multiprocessing.managers import SharedMemoryManager
    from multiprocessing.shared_memory import SharedMemory

    consumer_process_count = 3

    with SharedMemoryManager() as memory_manager:
        shared_memories = []
        memory_names = []
        for i in range(consumer_process_count):
            shared_memory = memory_manager.SharedMemory(size=1)
            shared_memories.append(shared_memory)
            memory_names.append(shared_memory.name)
            print(f"Memory {shared_memory.name} created.")

        for memory_name in memory_names:
            try:
                SharedMemory(name=memory_name)
            except FileNotFoundError:
                print(f"Memory {memory_name} not found.")
            else:
                print(f"Memory {memory_name} found.")

打印:

Memory wnsm_5e0842b0 created.
Memory wnsm_1a9758ac created.
Memory wnsm_e93c9e19 created.
Memory wnsm_5e0842b0 found.
Memory wnsm_1a9758ac found.
Memory wnsm_e93c9e19 found

解释

查看库代码,当共享内存管理器创建共享内存块时,它只保留共享内存的名称,而不保留对返回给调用者的

multiprocessing.shared_memory
实例的实际引用。当不再有对实际内存的引用时(这发生在原始代码中),将在实例上调用方法
__del__
,该方法会在共享内存块上发出对
close()
的调用。所以严格来说,共享内存块并没有被这个动作“取消链接”,而是根据
close()
的文档:

关闭从此实例对共享内存的访问。为了确保正确清理资源,一旦不再需要实例,所有实例都应该调用 close()。请注意,调用 close() 不会导致共享内存块本身被销毁。

因此该块可能仍然存在,但无法再访问。

© www.soinside.com 2019 - 2024. All rights reserved.