如何获取python的多处理数组'指针并将其传递给Cpp程序?

Posted

技术标签:

【中文标题】如何获取python的多处理数组\'指针并将其传递给Cpp程序?【英文标题】:How to get python's multiprocessing array'pointer and pass it to Cpp program?如何获取python的多处理数组'指针并将其传递给Cpp程序? 【发布时间】:2020-06-22 10:19:41 【问题描述】:

我现在需要在 python 中请求数组,并将它们传递给 Cpp 程序,但 python 仍然需要处理它们。但是我发现当我使用多处理时,数组的地址会改变。

以下是我的代码:

//在test.h中导出dll,这个是test.cpp
#include “test.h”
#include 
使用命名空间标准;

无效的一些工作(双*数据,长*标志)
    cout 
# test.py
import multiprocessing as mp
from multiprocessing.sharedctypes import RawArray
import ctypes

data = RawArray(ctypes.c_double, 2000)
flag = RawArray(ctypes.c_long, 20)
pkg = ctypes.cdll.LoadLibrary(r"test.dll")
pkg.someWork.argtypes = [
    ctypes.POINTER(ctypes.c_double * 2000),# dataArray
    ctypes.POINTER(ctypes.c_long * 20)#flagArray
]

def proc_py():
    idx = 0
    while True:
        if flag[idx] == 1:
            # do something
            flag[idx] = 0
            idx = (idx + 1) % 20

def proc_cpp():
    pkg.someWork(ctypes.pointer(data), ctypes.pointer(flag))

def main():
    p_cpp = mp.Process(target=proc_cpp, args=())
    p_py = mp.Process(target=proc_py, args=())
    p_cpp .start()
    p_py .start()
    p_cpp .join()
    p_py .join()

if __name__ == '__main__':
    print("py flag address:", ctypes.byref(flag))
    # proc_cpp()
    main()

结果是:我刚刚在python中运行proc_cpp,地址是一样的:

py flag address: <cparam 'P' (0000019DA8282400)>
cpp flag address:   0000019DA8282400

但是当我运行main时,地址不同:

py flag address: <cparam 'P' (000001CB42A32400)>
cpp flag address:   0000012F1E152400

我知道python的多处理必须使用共享内存在处理之间共享内存,但是我使用mp.Array/Array.get_obj()mp.sharedctypes.RawArray/ctypes.pointer()都失败了。有什么办法可以解决我的问题吗?

【问题讨论】:

共享内存不一定映射到不同进程中的相同虚拟地址。不要期望地址匹配。 @MarkTolonen 谢谢你的回复,但似乎如果我想将数组传递给 c/cpp 程序,我必须传递指针。有什么建议可以满足 c/cpp 和 python 可以在多处理任务中使用共享数组的要求吗? 【参考方案1】:

不要在“运行一次”主代码之外创建RawArray,否则您正在制作不同 数组。在主进程中创建一次RawArray,并将RawArray 作为参数传递给新进程的目标函数。每个进程“看到”的虚拟地址是不同的,但物理内存是一样的。

这是一个例子:

test.cpp:

这将显示指针地址,然后更改共享数组中的指定索引。

#include <iostream>
#include <cstdint>
using namespace std;

#define API __declspec(dllexport)

extern "C" API
void set(double* data, int index, double value) 
    cout << data << ' ' << index << ' ' << value << endl;
    data[index] = value;

test.py:

这会将共享数组传递给每个进程。主进程也会改变一个元素。使用锁是因为 RawArray 不同步,否则 C++ 代码中的打印会混乱,所以这段代码不会真正并行运行,但它确实说明了进程获得不同的虚拟地址但共享相同的数据。

import multiprocessing as mp
from multiprocessing.sharedctypes import RawArray
from ctypes import *

dll = CDLL('./test')
dll.set.argtypes = POINTER(c_double),c_int,c_double
dll.set.restype = None

def call(lock,data,index,value):
    with lock:
        dll.set(data,index,value)

if __name__ == '__main__':

    # This code runs once in the main process.
    # The lock and shared data are created once only and passed to other processes.

    lock = mp.Lock()
    data = RawArray(c_double, 3)
    data[0] = 0.5
    p1 = mp.Process(target=call, args=(lock,data,1,1.25))
    p2 = mp.Process(target=call, args=(lock,data,2,2.5))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    print(list(data))

输出(不同的地址,相同的共享数据):

00000269D66E0000 1 1.25
00000187F0B90000 2 2.5
[0.5, 1.25, 2.5]

【讨论】:

我以为调用cpp程序时py必须通过ctypes.byrefctypes.pointer传递arryay,但不知道它可以直接传递python数组。这个答案很有用,谢谢! @ChuangMen 它模仿 C 将数组衰减传递给指针。 ctypes.argtypes 定义中知道正确的类型。

以上是关于如何获取python的多处理数组'指针并将其传递给Cpp程序?的主要内容,如果未能解决你的问题,请参考以下文章

如何正确传递带有指向函数的指针的数组?

Python & Ctypes:将结构作为指针传递给函数以获取数据

获取 SQLite 数据库并将其存储在对象数组中

有没有办法获取传递给函数的数组的大小?

从mysql表中获取行到php数组并将其传递给ajax

如何从小部件的函数返回值,并将其传递给 Tkinter,Python 中的另一个小部件的函数