Numpy数组因ndpointer而生锈,在Windows中失败(在Linux上工作)
目的:通过ctypes将np.ASCONTIGOUUSARRAY传递给Rust函数。Rust会对阵列进行各种更改。进程在Python中继续。代码在Linux环境中按预期运行(Linux上内置的rust cargo stable,从Manjaro 4.19内核中的Python 3.8调用),但会引发错误:OSError:exception:访问冲突读取0xFFFFFFFFFFFF(有关Windows构建条件,请参阅下文) (简化)代码: 实际生锈功能更复杂。这个小小的剪报足以证明它在Linux中工作,同时在Windows中引发了一个例外Numpy数组因ndpointer而生锈,在Windows中失败(在Linux上工作),numpy,rust,ffi,Numpy,Rust,Ffi,目的:通过ctypes将np.ASCONTIGOUUSARRAY传递给Rust函数。Rust会对阵列进行各种更改。进程在Python中继续。代码在Linux环境中按预期运行(Linux上内置的rust cargo stable,从Manjaro 4.19内核中的Python 3.8调用),但会引发错误:OSError:exception:访问冲突读取0xFFFFFFFFFFFF(有关Windows构建条件,请参阅下文) (简化)代码: 实际生锈功能更复杂。这个小小的剪报足以证明它在Linux中工
//Rust:
#[no_mangle]
pub extern "C" fn proc_array(data: &mut [f64], count : usize) -> usize {
println!("In Windows Array Test: received {} items...", count);
let e = count - 1;
// Next Line is where the exception is raised:
println!("Start & End: {:.4}, {:.4}", data[0], data[e]);
data[0] += 200.0;
data[e] *= 2.0;
println!("Start & End: {:.4}, {:.4}", data[0], data[e]);
let pairs : usize = count / 2;
pairs
}
我知道异常是在它第一次尝试读取数据[0]
的行中引发的(我还运行了一些更简短的版本,其中还涉及到例如let x:f64=data[0]
,以证明引发异常的是对数据[0]
的第一次读取操作。)
也知道:windows版本是在windows中的rust cargo下编译的。 如果使用windows gnu或windows msvc工具链编译,则行为相同。 在所有情况下:
print(十六进制(c.uu数组uu接口uu['data']][0])
显示c数组
的地址,例如0x225108514c0
,这是预期的,当然不是0xfffffffffff(它指向月球,当然在我的32GB内存中没有任何地方…)
我的结论是,windows中的Python传递指针的方式与Linux中的不同,在windows下我需要以不同的方式传递指针,但在我的搜索中,我没有发现任何东西能够回答这一点。遵循Jmb的建议 及
- ,
- 来自Rust编译器的“帮助”响应
struct Node {
x : f64,
y : f64,
// ... (real version has additional fields used elsewhere)
}
#[no_mangle]
pub extern "C" fn array_test(dptr: *mut f64, count : usize) -> usize {
println!("In Windows Array Test: received {} items...", count);
let data : &mut[f64] = unsafe {
assert!(!dptr.is_null());
std::slice::from_raw_parts_mut(dptr, count)
};
let pairs : usize = count / 2;
// populate the structs
let mut nodes : Vec<Node> = Vec::with_capacity(pairs);
for i in (0..count).filter(|x| (x % 2 == 0)) {
nodes.push(Node { x: data[i], y : data[i+1] } );
}
// actual detail of the changes made to the data
// not relevant to this question
// write x & y's back to the data buffer
for i in 0..pairs {
data[i * 2] = nodes[i].x;
data[(i * 2) + 1] = nodes [i].y;
}
// placeholder return:
pairs
}
结构节点{
x:f64,
y:f64,
//…(真实版本在其他地方使用了其他字段)
}
#[没有损坏]
发布外部“C”fn数组_测试(dptr:*mut f64,计数:usize)->usize{
println!(“在Windows数组测试中:收到{}项…”,计数);
let数据:&mut[f64]=不安全{
断言!(!dptr.is_null());
标准::切片::来自原始零件(dptr,计数)
};
let pairs:usize=count/2;
//填充结构
让mut节点:Vec=Vec::具有_容量(对);
对于(0..count.filter(|x |(x%2==0))中的i{
push(节点{x:data[i],y:data[i+1]});
}
//对数据所做更改的实际详细信息
//与这个问题无关
//将x&y写回数据缓冲区
对我来说,一对一对{
数据[i*2]=节点[i].x;
数据[(i*2)+1]=节点[i].y;
}
//占位符返回:
对
}
这在两个环境Win 10普通linux中进行了测试(在我使用的系统中…很抱歉,我刚才没有能力在其他配置上测试此方法)rust函数的
数据参数应该是指向f64
的指针,而不是一个片段。请参阅:返回类型之间也存在不匹配。Rust代码返回一个u32
,但是Python代码声明process\u array.restype=ctypes.c\u size\u t
。并且直接传递一个numpy数组(假设它是指向c样式数组的指针)似乎也有点过于乐观。也许是个好主意。这些评论都帮了大忙。只要我有足够的分数,我就会回来加选票!
struct Node {
x : f64,
y : f64,
// ... (real version has additional fields used elsewhere)
}
#[no_mangle]
pub extern "C" fn array_test(dptr: *mut f64, count : usize) -> usize {
println!("In Windows Array Test: received {} items...", count);
let data : &mut[f64] = unsafe {
assert!(!dptr.is_null());
std::slice::from_raw_parts_mut(dptr, count)
};
let pairs : usize = count / 2;
// populate the structs
let mut nodes : Vec<Node> = Vec::with_capacity(pairs);
for i in (0..count).filter(|x| (x % 2 == 0)) {
nodes.push(Node { x: data[i], y : data[i+1] } );
}
// actual detail of the changes made to the data
// not relevant to this question
// write x & y's back to the data buffer
for i in 0..pairs {
data[i * 2] = nodes[i].x;
data[(i * 2) + 1] = nodes [i].y;
}
// placeholder return:
pairs
}