Python 和 C++ 共享相同的内存资源

Posted

技术标签:

【中文标题】Python 和 C++ 共享相同的内存资源【英文标题】:Python and C++ sharing the same memory resources 【发布时间】:2018-02-13 22:15:37 【问题描述】:

假设我们正在使用 Python 并调用一些用 C++ 编写的 DLL 库。我们在 Python 中打开一个非常大的数据集,然后我们想调用一个用 C++ 编写的库,并添加一个以打开的数据作为参数的数组。库会对该数组进行处理,然后将其返回给 Python 代码。

所以问题是:是否可以使用内存的相同位置? 因为在那种情况下,我们不需要复制大量数据两次。

【问题讨论】:

考虑使用内存映射文件。例如使用 mmap。哪个操作系统? 微软视窗 10 看看这个:***.com/questions/26114518/… 是用于进程间通信的,不过还是可以私下使用的。 【参考方案1】:

这一切都取决于您如何将数据加载到内存中以及它是什么类型的数据。

如果它是数字数据并且您使用例如一个 numpy 数组,它已经存储了一个内存布局,可以从 C 或 C++ 代码中轻松使用。很容易获得数据块的地址(numpy.ndarray.ctypes.data)并通过 ctypes 将其传递给 C++ 代码。你可以看到一个很好的例子here。图像数据在这方面是类似的(PIL 图像是简单的内存格式,可以很容易地获得指向它们数据的指针)。

另一方面,如果您的数据位于常规的“本机”Python 结构(例如常规列表或常规对象)中,情况会更加棘手。您可以将它们直接传递给 C++ 代码,但它是必须了解 Python 数据结构的代码 - 因此,专门为此目的编写,使用 python.h 并处理非平凡的 Python API。

【讨论】:

谢谢!但是我目前正在使用 Shiboken 包装器,因为我正在使用 PySide2 来调用用 C++ 编写的 Qt 我经常在 SIP/PyQt 扩展中在 Python 和 C++ 之间共享大型数据集,因此应该可以轻松实现。在这种情况下,通常您将数据保存在 C++ 端并为 Python 导出访问器。但同样,这一切都取决于您想要共享的数据集;您应该为您的问题添加更多详细信息。【参考方案2】:

这适用于内存映射文件。我不以任何方式声称高速或高效。这些只是为了展示它的工作示例。

 $ python --version
 Python 3.7.9

 $ g++ --version
 g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0

C++ 端只监控它需要的值。 Python 端只提供值。

注意:文件名“pods.txt”在C++和python代码中必须一致。

#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
 
int main(void)
  
  // assume file exists
  int fd = -1;
  if ((fd = open("pods.txt", O_RDWR, 0)) == -1)
     
     printf("unable to open pods.txt\n");
     return 0;
     
  // open the file in shared memory
  char* shared = (char*) mmap(NULL, 8, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

  // periodically read the file contents
  while (true)
      
      printf("0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n", shared[0], shared[1], shared[2], shared[3], shared[4], shared[5],           shared[6], shared[7]);
      sleep(1);
      

   return 0;
   

python方面:

import mmap
import os
import time
 
fname = './pods.txt'
if not os.path.isfile(fname):
    # create initial file
    with open(fname, "w+b") as fd:
         fd.write(b'\x01\x00\x00\x00\x00\x00\x00\x00')

# at this point, file exists, so memory map it
with open(fname, "r+b") as fd:
    mm = mmap.mmap(fd.fileno(), 8, access=mmap.ACCESS_WRITE, offset=0)

    # set one of the pods to true (== 0x01) all the rest to false
    posn = 0
    while True:
         print(f'writing posn:posn')

         # reset to the start of the file
         mm.seek(0)
 
         # write the true/false values, only one is true
         for count in range(8):
             curr = b'\x01' if count == posn else b'\x00'
             mm.write(curr)

         # admire the view
         time.sleep(2)

         # set up for the next position in the next loop
        posn = (posn + 1) % 8

    mm.close()
    fd.close()

要在终端 #1 中运行它:

 a.out  # or whatever you called the C++ executable
 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00
 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00
 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00
 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00
 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00
 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00
 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x00
 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x00
 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x00

即由于 C++ 代码中的 sleep(2),您应该会看到 0x01 每隔几秒移动一步。

在 2 号航站楼:

python my.py  # or whatever you called the python file
writing posn:0
writing posn:1
writing posn:2

即您应该会看到位置从 0 到 7 再次变回 0。

【讨论】:

以上是关于Python 和 C++ 共享相同的内存资源的主要内容,如果未能解决你的问题,请参考以下文章

如何使用共享内存在 cpp 和 python 之间共享 cv::Mat 以进行处理

在 C++ 和 Python 之间共享视频数据

如何在python和C / C ++中使用共享内存

Python - 多处理和共享内存

Python中多进程的使用

从 python 中的共享库返回的数组 - 这是内存泄漏吗?