从Python传递大型复杂数组到C-我最好的选择是什么?
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了从Python传递大型复杂数组到C-我最好的选择是什么?,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4093字,纯文字阅读大概需要6分钟。
内容图文
2017/06/13编辑:
我尝试按照建议的方法使用boost,但是在花了3天以上的时间尝试使其进行编译和链接后,失败了,我认为这种愚蠢的痛苦方式可能是最快且痛苦更少的方式.保存一堆C然后读取的硕大的文本文件(拆分数组和数字在文件中的复数/虚数部分).优雅…不…有效…是.
我有一些科学代码,当前使用Python编写,但由于循环内的数字3d集成步骤而使其速度变慢.为了克服这个问题,我正在C中重写此特定步骤. (Cython等不是选项).
长话短说:我想尽可能方便和轻松地将数个非常大的复数数组从python代码传输到C集成器.我可以手动使用文本或二进制文件来完成此操作,但是在进行此操作之前,我想知道是否有更好的选择?
我正在使用Visual Studio C和PythonPython(不是我的选择!)
是否有任何文件格式或方法可以快速方便地从python保存复数数组,然后在C中重新创建它?
非常感谢,
本
解决方法:
我多次使用的简单解决方案是将您的“ C端”构建为dll(= Linux / OS X上的共享对象),提供一个简单的,类似于C的入口点(直整数,指针& co.,没有STL)东西)并通过ctypes传递数据.
这避免了boost / SIP / Swig / …构建梦mar,可以保持零复制(使用ctypes可以将直指针指向numpy数据),并允许您做任何您想做的事情(尤其是在构建方面-没有friggin的distutils,没有提升,什么都没有-用可以在C端构建类似于C的dll的方式进行构建.让您的C算法可以从其他语言中调用也具有很好的副作用(实际上,任何一种语言都可以通过某种方式与C库进行接口).
Here是一个快速的人工示例. C边就是:
extern "C" {
double sum_it(double *array, int size) {
double ret = 0.;
for(int i=0; i<size; ++i) {
ret += array[i];
}
return ret;
}
}
必须将其编译为dll(在Windows上)或.so(在Linux上),并确保导出sum_it函数(使用gcc自动运行,需要使用VC的.def文件).
在Python方面,我们可以使用类似
import ctypes
import os
import sys
import numpy as np
path = os.path.dirname(__file__)
cdll = ctypes.CDLL(os.path.join(path, "summer.dll" if sys.platform.startswith("win") else "summer.so"))
_sum_it = cdll.sum_it
_sum_it.restype = ctypes.c_double
def sum_it(l):
if isinstance(l, np.ndarray) and l.dtype == np.float64 and len(l.shape)==1:
# it's already a numpy array with the right features - go zero-copy
a = l.ctypes.data
else:
# it's a list or something else - try to create a copy
arr_t = ctypes.c_double * len(l)
a = arr_t(*l)
return _sum_it(a, len(l))
确保数据正确封送;然后调用该函数就很简单
import summer
import numpy as np
# from a list (with copy)
print summer.sum_it([1, 2, 3, 4.5])
# from a numpy array of the right type - zero-copy
print summer.sum_it(np.array([3., 4., 5.]))
有关如何使用它的更多信息,请参见ctypes documentation.另请参见the relevant documentation in numpy.
对于复数,情况要稍微复杂一些,因为ctypes中没有内置函数.如果我们想使用std :: complex< double>在C侧(对于numpy复杂布局,它是pretty much guaranteed可以正常工作,即两个双精度数的序列),我们可以将C侧写为:
extern "C" {
std::complex<double> sum_it_cplx(std::complex<double> *array, int size) {
std::complex<double> ret(0., 0.);
for(int i=0; i<size; ++i) {
ret += array[i];
}
return ret;
}
}
然后,在Python端,我们必须复制c_complex布局以获取返回值(或能够构建没有numpy的复杂数组):
class c_complex(ctypes.Structure):
# Complex number, compatible with std::complex layout
_fields_ = [("real", ctypes.c_double), ("imag", ctypes.c_double)]
def __init__(self, pycomplex):
# Init from Python complex
self.real = pycomplex.real
self.imag = pycomplex.imag
def to_complex(self):
# Convert to Python complex
return self.real + (1.j) * self.imag
从ctypes继承.Structure启用ctypes编组魔术,这是根据_fields_成员执行的;构造函数和其他方法只是为了在Python方面易于使用.
然后,我们必须告诉ctypes返回类型
_sum_it_cplx = cdll.sum_it_cplx
_sum_it_cplx.restype = c_complex
最后以与上一个类似的方式编写我们的包装器:
def sum_it_cplx(l):
if isinstance(l, np.ndarray) and l.dtype == np.complex and len(l.shape)==1:
# the numpy array layout for complexes (sequence of two double) is already
# compatible with std::complex (see https://stackoverflow.com/a/5020268/214671)
a = l.ctypes.data
else:
# otherwise, try to build our c_complex
arr_t = c_complex * len(l)
a = arr_t(*(c_complex(r) for r in l))
ret = _sum_it_cplx(a, len(l))
return ret.to_complex()
如上测试
# from a complex list (with copy)
print summer.sum_it_cplx([1. + 0.j, 0 + 1.j, 2 + 2.j])
# from a numpy array of the right type - zero-copy
print summer.sum_it_cplx(np.array([1. + 0.j, 0 + 1.j, 2 + 2.j]))
产生预期的结果:
(3+3j)
(3+3j)
内容总结
以上是互联网集市为您收集整理的从Python传递大型复杂数组到C-我最好的选择是什么?全部内容,希望文章能够帮你解决从Python传递大型复杂数组到C-我最好的选择是什么?所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。