如何获取python's multiprocessing array'指针并将其传递给Cpp程序?
How to get python's multiprocessing array'pointer and pass it to Cpp program?
我现在需要在 python 中请求数组,并将它们传递给 Cpp 程序,但 python 仍然需要处理它们。但是我发现当我使用multiprocessing时,数组的地址会被改变。
下面是我的代码:
//export dll in test.h, this is test.cpp
#include "test.h"
#include <iostream>
using namespace std;
void someWork(double* data, long* flag){
cout << "cpp flag address:" << flag << endl;
//do some work
}
# 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()
。有什么办法可以解决我的问题吗?
不要在“运行 once”主代码之外创建 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]
我现在需要在 python 中请求数组,并将它们传递给 Cpp 程序,但 python 仍然需要处理它们。但是我发现当我使用multiprocessing时,数组的地址会被改变。
下面是我的代码:
//export dll in test.h, this is test.cpp #include "test.h" #include <iostream> using namespace std; void someWork(double* data, long* flag){ cout << "cpp flag address:" << flag << endl; //do some work }
# 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()
。有什么办法可以解决我的问题吗?
不要在“运行 once”主代码之外创建 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]