【问题标题】:Passing shared memory object between two processes via socket in Python在 Python 中通过套接字在两个进程之间传递共享内存对象
【发布时间】:2017-04-18 22:34:14
【问题描述】:

我的应用程序由两个通过 TCP 套接字连接的 Python 进程组成。第一个进程旨在读取文件并将它们放入共享内存中,而不是向下推套接字,以便其他进程可以读取它们。

import os
import zmq
import mmap
import time
import ctypes
import pickle
import dill
import tempfile
import multiprocessing as mp

MEETING_POINT = 'tcp://127.0.0.1:12345'
FILEFD, FILEPATH = tempfile.mkstemp()


def run_server():
    Server().run()


def read_file():
    return open(FILEPATH, 'r').read()


class Client(object):
    def __init__(self):
        self.ctx = zmq.Context()
        self.socket = self.ctx.socket(zmq.DEALER)
        self.socket.connect(MEETING_POINT)

    def cleanup(self):
        self.socket.close()
        self.ctx.term()

    def run(self):
        self.socket.send(dill.dumps(read_file()))


class Server(object):
    def __init__(self):
        self.ctx = zmq.Context()
        self.socket = self.ctx.socket(zmq.DEALER)
        self.socket.bind(MEETING_POINT)

    def cleanup(self):
        self.socket.close()
        self.ctx.term()

    def run(self):
        f = dill.loads(self.socket.recv())
        print(f)


def main():
    with open(FILEPATH, 'w') as fd:
        fd.write('blah')

    mp.Process(target=run_server).start()
    time.sleep(.5)  # a (poor, but tolerable) alternative to handshaking
    Client().run()


if __name__ == '__main__':
    main()

我的问题归结为:如何通过套接字传递有关第二个进程要访问的内存段的信息?我尝试了以下方法(pickledill),但均无济于事:

  • 直接在文件上使用mmap.mmap 或存储其内容。结果:TypeError: Required argument 'fileno' (pos 1) not found 在服务器端解压时。

  • 使用 multiprocessing.Array:

    with open(FILEPATH, 'r') as fd: contents = bytearray(fd.read()) arr = mp.Array(ctypes.c_byte, contents, lock=False)

结果:pickle.PicklingError: Can't pickle <class 'multiprocessing.sharedctypes.c_byte_Array_4'>: it's not found as multiprocessing.sharedctypes.c_byte_Array_4 在客户端酸洗时。

我相信有一种更简单(且有效)的方法可以做到这一点,是吗?在创建服务器进程时,我无法预先读取所有必要的文件并将它们打包成multiprocessing.Array 以作为args 传递,当然这会(据说)解决所有问题。

【问题讨论】:

    标签: python sockets multiprocessing shared-memory


    【解决方案1】:

    回答我自己的问题,因为我知道我要确切地做什么。根据man mmap,为了让第二个进程能够读取第一个进程的内存,创建一个带有MAP_SHARED 标志的内存段就足够了。因此,就像在mmap.mmap 的构造函数中一样,这个标志是默认设置的,所要做的就是传递文件名而不是类实例:

    # sometime during the first process' execution
    fd = open(filepath_to_process, 'w')
    memory = mmap.mmap(fd.fileno(), 0)
    socket.send(filepath_to_process)
    
    # on the other side of socket, this happens:
    unprocessed_filepath = socket.recv()
    fresh_fd = open(unprocessed_filepath, 'r')
    mm = mmap.mmap(fresh_fd.fileno(), 0)
    
    # voilà! All the changes are now propagated to the second process
    

    当然,文件和内存区域的访问模式必须匹配,但man mmap 中有一个单独的部分,称为“ERRORS”

    对于共享内存,有posix_ipcsysv_ipc模块(后者支持更广泛的操作系统)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-22
      相关资源
      最近更新 更多