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

8
假设我们正在使用Python并调用一些用C ++编写的DLL库。我们在Python中打开了一个非常大的数据集,然后我们想调用一个用C ++编写的库,并将具有打开的数据的数组作为参数添加。库将对该数组执行某些操作,然后将其返回到Python代码。
那么问题是:是否可以使用相同的内存位置?因为在这种情况下,我们不需要复制大量数据两次。

考虑使用内存映射文件,例如使用 mmap。使用哪个操作系统? - cdarke
微软 Windows 10 - Matphy
1
看一下这个链接:https://dev59.com/MYPba4cB1Zd3GeqPx9ga。它是关于进程间通信的,但仍然可以私下使用。 - cdarke
2个回答

5
一切取决于如何将数据加载到内存中以及数据的类型。如果是数字数据并且使用numpy数组,则已经采用轻松可用于C或C++代码的内存布局存储。很容易获得数据块的地址(numpy.ndarray.ctypes.data),并通过ctypes将其传递给C++代码。您可以在这里看到一个很好的例子。图像数据在这方面也类似(PIL图像采用简单的内存格式,可以轻松获得其数据的指针)。
另一方面,如果您的数据是常规的“本地”Python结构(例如常规列表或常规对象),情况就更加棘手了。您可以直接将它们传递到C++代码,但必须知道有关Python数据结构的代码 - 因此,专门为此目的编写,使用python.h并处理非平凡的Python API。

谢谢!不过我目前正在使用Shiboken包装器,因为我正在使用PySide2来调用用C++编写的Qt - Matphy
我经常在SIP/PyQt扩展中在Python和C++之间共享大型数据集,因此应该可以轻松完成。在这种情况下,通常您将数据保存在C++端,并导出Python的访问器。但是,一切都取决于您想要共享的数据集的具体内容;您应该在问题中添加更多细节。 - Matteo Italia

2

这是使用内存映射文件实现的。我不会以任何方式声称高速或高效。这只是为了展示其工作原理的示例。

 $ python --version
 Python 3.7.9

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

C++端只监控其需要的值,Python端只提供这些值。
注意:在C++和Python代码中,“pods.txt”文件名必须相同。
#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每隔几秒钟移动一步。

在第二个终端中:

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

即,您应该看到位置从0经过7再次返回到0。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接