【问题标题】:How To Use Memory Mapped File in Python Linux如何在 Python Linux 中使用内存映射文件
【发布时间】:2020-08-24 01:40:57
【问题描述】:

正如我在 Python 文档中看到的,

https://docs.python.org/3/library/mmap.html.

Linux 中的 Python 可以完全支持内存映射文件。然而,当我试图将这个想法应用到我的应用程序时。我无法运行示例。

我的应用程序是将帧从 Python 文件(客户端)发送到另一个 Python 文件(服务器)。

客户代码

import mmap
import time
import os
import cv2 as cv

print("Opening camera...")
cap = cv.VideoCapture('/home/hunglv/Downloads/IMG_8442.MOV')

mm = None
try:
    while True:
        ret, img = cap.read()
        if not ret:
            break
        if mm is None:
            mm = mmap.mmap(-1,img.size,mmap.MAP_SHARED, mmap.PROT_WRITE)

        # write image
        start = time.time()
        buf = img.tobytes()
        mm.seek(0)
        mm.write(buf)
        mm.flush()  
        stop = time.time()
        print("Writing Duration:", (stop - start) * 1000, "ms")
except KeyboardInterrupt:
    pass
print("Closing resources")
cap.release()
mm.close()

服务器代码

import mmap
import time
import os
import cv2 as cv
import numpy as np

shape = (1080, 1920, 3)
n = np.prod(shape)
mm = mmap.mmap(-1, n)

while True:
    # read image
    print (mm)
    start = time.perf_counter()
    mm.seek(0)
    buf = mm.read(12)
    img = np.frombuffer(buf, dtype=np.uint8).reshape(shape)
    stop = time.perf_counter()

    print("Reading Duration:", (stop - start) * 1000, "ms")
    cv.imshow("img", img)
    key = cv.waitKey(1) & 0xFF
    key = chr(key)
    if key.lower() == "q":
        break
cv.destroyAllWindows()
mm.close()

在服务器端,我将内存索引设置为 0,并尝试从内存中读取字节。但是,似乎服务器无法正确读取来自客户端的数据。

[更新] 我试图在服务器端读出前 12 个字节。该值是恒定的,不再变化。

b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

此外, 随机帧的前 12 个字节是

b'\xf5\xff\xff\xf0\xfa\xfe\xdf\xe9\xed\xd2\xdc\xe0'

【问题讨论】:

  • 您收到什么错误?数据是否不正确或根本没有读取?
  • @rassar 我已将信息添加到帖子中。从内存中读取的数据是一样的。
  • 对于我在mmap() 中使用-1,您创建了两个分开的mmaps,两个程序使用不同的mmap。您必须在 mmaps 中使用相同的 fileno
  • 也许您应该使用shared-memorypipessockets 从一个进程发送到另一个。
  • 在文档中,-1 是匿名内存,我试过用另一个号码,但它说找不到号码。我认为这两个 Python 文件会创建不同的 mmaps (两个不同的对象)。这就是为什么服务器不理解客户端中的mmaps 的原因。

标签: python image frames


【解决方案1】:

首先我找到了可能有效但它使用tagName(客户端和服务器相同)的示例,这意味着它仅适用于Window:

python-mmap-ipc


接下来我找到了适用于 Linux 的代码:

Sharing Python data between processes using mmap.

它在磁盘上创建真实文件,将其调整为图像大小,然后在mmap() 中使用其fd


我使用网络摄像头进行测试。

服务器

import mmap
import time
import os
import cv2

print("Opening camera...")

cap = cv2.VideoCapture(0)
#print(cap.get(cv.CAP_PROP_FRAME_WIDTH))  # 640
#print(cap.get(cv.CAP_PROP_FRAME_HEIGHT)) # 480

shape = (480, 640, 3)
n = (480*640*3)

fd = os.open('/tmp/mmaptest', os.O_CREAT | os.O_TRUNC | os.O_RDWR)
#os.write(fd, b'\x00' * n)  # resize file
os.truncate(fd, n)  # resize file

mm = None
try:
    while True:
        ret, img = cap.read()
        
        if not ret:
            break
        
        if mm is None:
            mm = mmap.mmap(fd, n, mmap.MAP_SHARED, mmap.PROT_WRITE)  # it has to be only for writing

        # write image
        start = time.perf_counter()
        
        buf = img.tobytes()
        mm.seek(0)
        mm.write(buf)
        mm.flush()
        
        stop = time.perf_counter()

        print("Writing Duration:", (stop - start) * 1000, "ms")
except KeyboardInterrupt:
    pass

print("Closing resources")
cap.release()
mm.close()

客户

import mmap
import time
import os
import cv2
import numpy as np

shape = (480, 640, 3)
n = (480*640*3)

fd = os.open('/tmp/mmaptest', os.O_RDONLY)

mm = mmap.mmap(fd, n, mmap.MAP_SHARED, mmap.PROT_READ)  # it has to be only for reading

while True:
    # read image
    start = time.perf_counter()
    
    mm.seek(0)
    buf = mm.read(n)
    img = np.frombuffer(buf, dtype=np.uint8).reshape(shape)
    
    stop = time.perf_counter()

    print("Reading Duration:", (stop - start) * 1000, "ms")

    cv2.imshow("img", img)
    key = cv2.waitKey(1) & 0xFF
    key = chr(key)
    if key.lower() == "q":
        break
    
cv2.destroyAllWindows()
mm.close()

顺便说一句:可能mmap()-1(无需在磁盘上创建文件)可以与线程(或分叉)一起使用,因为它们共享相同的内存。

【讨论】:

  • 非常感谢您的解决方案。现在我可以完全理解mmap背后的机制了。我对您的解决方案感到非常满意。基本上,我们需要分配系统中的临时文件(虚拟文件),并告诉两个程序访问同一个文件。 > github.com/off99555/python-mmap-ipc 我的方法与上面的链接相同(不幸的是仅适用于Window)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-18
  • 2014-03-04
  • 2019-05-08
相关资源
最近更新 更多