简体   繁体   English

在进程之间共享只读对象

[英]Share read-only objects between processes

I use a "keep alive" processes model (who communicates with Pipes with main process) in my software, and I'm trying to share read-only objects between them and the main process. 我在软件中使用了“保持活动”流程模型(该流程模型与主流程与Pipes进行通信),并且试图在它们和主流程之间共享只读对象。 An example to show my problem: 一个显示我的问题的例子:

from multiprocessing import Process, Pipe#, Manager
from multiprocessing.connection import wait
import os


def start_in_oneshot_processes(obj, nb_process):
    """
    Start nb_process processes to do the job. Then process finish the job they die.
    """
    processes = []
    for i in range(nb_process):
        #  Simple process style
        p = Process(target=oneshot_in_process, args=(obj,))
        p.start()
        processes.append(p)

    for process in processes:
        # Wait all process finish
        process.join()

def oneshot_in_process(obj):
    """
    Main job (don't matter if in oneshot, keeped alive process. It have job to do)
    """
    print('p', obj, os.getpid())


def start_in_keepedalive_processes(obj, nb_process):
    """
    Start nb_process and keep them alive. Send job to them multiple times, then close thems.
    """
    processes = []
    readers_pipes = []
    writers_pipes = []
    for i in range(nb_process):
        # Start process with Pipes for communicate
        local_read_pipe, local_write_pipe = Pipe(duplex=False)
        process_read_pipe, process_write_pipe = Pipe(duplex=False)
        readers_pipes.append(local_read_pipe)
        writers_pipes.append(process_write_pipe)
        p = Process(target=run_keepedalive_process, args=(local_write_pipe, process_read_pipe, obj))
        p.start()
        processes.append(p)
    # Send to process some job to do
    for job in range(3):
        print('send new job to processes:')
        for process_number in range(nb_process):
            # Send data to process
            writers_pipes[process_number].send(obj)
            reader_useds = []
        # Wait response from processes
        while readers_pipes:
            for r in wait(readers_pipes):
                try:
                    r.recv()
                except EOFError:
                    pass
                finally:
                    reader_useds.append(r)
                    readers_pipes.remove(r)
        readers_pipes = reader_useds

    # Kill processes
    for writer_pipe in writers_pipes:
        writer_pipe.send('stop')

def run_keepedalive_process(main_write_pipe, process_read_pipe, obj):
    """
    Procees who don't finish while job to do
    """
    while obj != 'stop':
        oneshot_in_process(obj)
        # Send to main process "I've done my job"
        main_write_pipe.send('job is done')
        # Wait for new job to do (this part can be simplified no ?)
        readers = [process_read_pipe]
        while readers:
            for r in wait(readers):
                try:
                    obj = r.recv()
                except EOFError:
                    pass
                finally:
                    readers.remove(r)


obj = object()
print('m', obj, os.getpid())

print('One shot processes:')
start_in_oneshot_processes(obj, 5)

print('Keeped alive processes:')
start_in_keepedalive_processes(obj, 5)

print('f', obj, os.getpid())

Output is: 输出为:

➜  sandbox git:(dev/opt) ✗ python3.4 sharedd.py
m <object object at 0xb7266dc8> 3225
One shot processes:
p <object object at 0xb7266dc8> 3227
p <object object at 0xb7266dc8> 3226
p <object object at 0xb7266dc8> 3229
p <object object at 0xb7266dc8> 3228
p <object object at 0xb7266dc8> 3230
Keeped alive processes:
p <object object at 0xb7266dc8> 3231
p <object object at 0xb7266dc8> 3232
send new job to processes:
p <object object at 0xb7266dc8> 3235
p <object object at 0xb7266dc8> 3233
p <object object at 0xb7266dc8> 3234
p <object object at 0xb7266488> 3231
send new job to processes:
p <object object at 0xb7266488> 3232
p <object object at 0xb7266488> 3235
p <object object at 0xb7266488> 3234
p <object object at 0xb7266490> 3231
p <object object at 0xb7266488> 3233
p <object object at 0xb7266490> 3232
p <object object at 0xb7266490> 3235
p <object object at 0xb7266490> 3233
send new job to processes:
p <object object at 0xb7266488> 3232
p <object object at 0xb7266488> 3235
p <object object at 0xb7266490> 3234
p <object object at 0xb7266488> 3231
f <object object at 0xb7266dc8> 3225
p <object object at 0xb7266488> 3233
p <object object at 0xb7266488> 3234

If I create simple processes (start_in_oneshot_processes), obj have the same memory address in subprocess and in main process: 0xb7266dc8 . 如果我创建简单进程(start_in_oneshot_processes),则obj在子进程和主进程中具有相同的内存地址: 0xb7266dc8

But when my process receive objects with a Pipe (start_in_keepedalive_processes), objects memory address are not the same as the main process: example: 0xb7266488 instead of 0xb7266dc8 . 但是,当我的进程使用管道(start_in_keepedalive_processes)接收对象时,对象的内存地址与主进程的地址不同:例如: 0xb7266488而不是0xb7266dc8 These objects are read-only by sub processes. 这些对象是子进程只读的。 How can I share them between main process and subprocess (and save memory copy time) ? 如何在主进程和子进程之间共享它们(并节省内存复制时间)?

You can't achieve what you want using Pipe . 使用Pipe无法实现所需的功能。 When data is sent through a pipe to another process, that process has to store a copy of the data in its own address space --- a new object, in Python. 当数据通过管道发送到另一个进程时,该进程必须将数据的副本存储在其自己的地址空间中-在Python中是一个新对象。 Most other methods of shipping data between processes are the same. 在进程之间传送数据的大多数其他方法是相同的。

It's only coincidence that you saw the same memory address from the start_in_oneshot_process function, likely due to your choice of operating system. 巧合的是,您从start_in_oneshot_process函数中看到了相同的内存地址,这很可能是由于您选择的操作系统所致。 In general, two processes won't share the same RAM at all. 通常,两个进程根本不会共享相同的RAM。 (Check the Process docs section on Contexts and Start Methods for the differences between Windows spawn and Unix fork .) (查看“ 上下文和启动方法 ”的“ Process文档”部分,了解Windows spawn和Unix fork之间的区别。)

If it's really important that two processes can inspect the same chunk of memory, you can try either shared memory or an object manager process . 如果两个进程可以检查同一块内存真的很重要,则可以尝试共享内存或对象管理器进程 Note that those same docs tell you that this rarely a good idea. 请注意,这些相同的文档告诉您这很少是一个好主意。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM