跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • Cython 中如何调用 c++ 的模板库?
未分類
24 11 月 2020

Cython 中如何调用 c++ 的模板库?

Cython 中如何调用 c++ 的模板库?

資深大佬 : black11black 2

如题,最近有一个大量用到 python 中字典和列表寻址特性的科学计算函数,初步估算了一下循环次数在十亿级,纯 python 跑的非常慢,换到 pypy 以后加速快了三倍左右,但还是要等一分钟才能出结果。

于是想到能不能用 cython 加速,我以前 cython 都是了解皮毛,只跑过 helloworld 。 今天初步研究了一下感觉可行,按我的想法,因为要大量使用 python 列表,其加速方式大概就是要映射到 cpp 的 vector 了吧

在引入 stl 时遇到了无法引入的问题,有没有带佬指点一下哪错了

# 按我的理解安装 cython 时应该已经自带转换好的 stl 文件了吧 # 以下这段 C 库的引入是可以正常编译的 import cython from libc.stdlib cimport atoi from libc.string cimport memset  # 但是这里引入 CPP 的话却会报错 from libcpp.vector cimport vector 

另外求问一下关于 python 字典的映射方式,在 cython 中应该怎么处理。比如现在有一个长度不确定的字典 name_dict,估测长度在一百万左右, 我需要大量使用诸如 name_dict['tom'] , name_dict['sam'] 这类字符串寻址来搜寻具体对象,对象内容不复杂,可以映射为结构体,但是这个字典该怎么搞?

谢谢大家

大佬有話說 (25)

  • 資深大佬 : Tony042

    考虑下 pybind11 来进行 python 和 C++交互?

  • 資深大佬 : lovestudykid

    应该是 cimport cython 吧,报错也不说什么错这怎么 debug

  • 資深大佬 : lovestudykid

    我记得直接用 Python 原生的 dict 是比较快的,用 cpp 的 map 不一定快,也可能是我哪里没弄对

  • 主 資深大佬 : black11black

    @lovestudykid 兄,一共就四行 import,这还用再贴一下报错报了什么么。。。再说 cython 咋看报错信息啊,又没有解释器,我都是编译过程中看报错。

  • 主 資深大佬 : black11black

    @Tony042 是这样,现在情况是有一段 python 代码,预研一下 cython 如果合适的话准备改成 cython,看了一下你说的这个项目似乎是设计用来在已经有 cpp 代码的情况下接入 py 的

  • 資深大佬 : lovestudykid

    @black11black 因为 code 并没有问题,编译器的报错也是报错。你没设置 language = c++?

  • 主 資深大佬 : black11black

    @lovestudykid 感谢,是 c++声明的问题,一贴条里写了。另外出现了新的问题,带佬看看

  • 資深大佬 : lovestudykid

    @black11black 你可以试试 long long

  • 資深大佬 : lovestudykid

    BTW, 这是 c 和 gcc 环境的问题,跟 cython 没关系。在我这里没问题

  • 主 資深大佬 : black11black

    @lovestudykid OK,可能是 64 位 python 用了 32 位编译器问题,大概吧。应该怎么修正呢? cython 通过 pip 装的,我不知道他用什么方法调用的编译器

  • 資深大佬 : lovestudykid

    @black11black 直接从你 PATH 调用的,也可以在 setup.py 制定,看 cython 文档

  • 資深大佬 : xuboying

    主能不能顺带测测 numba 库的效率?

    个人感觉纯计算用了 jit 技术以后应该不会有太大的差别了吧?

  • 主 資深大佬 : black11black

    @lovestudykid 带佬指点一下怎么调,我在文档里搜索 compiler 相关的内容没看见能设置的选项,主要是这篇 https://cython.readthedocs.io/en/latest/src/userguide/source_files_and_compilation.html

  • 主 資深大佬 : black11black

    @xuboying numba 有些黑魔法,不太喜欢用,以前测试过一些场景比纯 C 语言运行还快,不明原因。我这个环境里 jit 和 C 还是有比较大速度差距的,pypy 感觉在一些结构的实现上效率跟原生没啥区别,比如这种大字典寻址的

  • 主 資深大佬 : black11black

    另外按照上老哥说的用 long long 类型以后确实程序能正常运行了。我测了一下,cython 里是有 sizeof 这个 bif 的,我测 void *p 是 8bit,而 long 是 4bit,整个人都是懵的。

  • 主 資深大佬 : black11black

    遍地采坑啊。

    又遇到一个问题,比如 python 当中,在循环过程中新建对象是个很正常的操作,比如下面这样

    class A:

    pass

    lst = list()

    for i in range(10):

    lst.append(A())

    但是在 cython 里并不能在循环内部进行 cdef,所以现在又卡了,不会循环新建对象。

  • 資深大佬 : mckelvin

    不要用写 Python 的思想去写 C++, 先想办法定义好胶水层的接口参数类型,一般不建议 vector 直接对应 list. 因为 list 里的内存无法直接变成 vector 可用的内存,不得不有内存拷贝发生。建议用朴素一些的数据结构,比如 double* . 数值计算大部分情况下 numpy 和 scipy 已经够用了,他们已经封装好了一些底层 C/C++实现的功能。

    数值不对这个问题大概率是溢出了。有些 64 位操作系统里 long 是 32bit 的。建议用 int64_t 这样的类型,这样明确它是 64bit 长度。

    “`
    In [16]: (1 + 1000000) / 2 * 1000000
    Out[16]: 500000000000

    In [17]: 1 << 32
    Out[17]: 4294967296
    “`

  • 資深大佬 : qbqbqbqb

    @black11black long 这个确实是个坑,64 位 Linux 里是 8 字节的,但 64 位 Windows 里是 4 字节的

  • 資深大佬 : xuboying

    @black11black #14 我以前遇到过 numba 的坑是依赖了他的类型推测导致执行不稳定,不知道这个是不是你提到的“黑魔法”,后来我去官网研究了他的形参类型声明以后,问题就完全解决了。如果这些你已经知道了,就忽略我的留言好了。btw,毕竟我没有看过汇编代码,了解程度就到这一层了。在我的图形计算的应用里效果还是相当让我满意的。

  • 資深大佬 : wevsty

    cpp 的 std::vector 是模板,模板本身只是个源码不使用的话本身并没有实例,你当然不可能用 python 直接调模板的源码。
    想要用 std::vector 的话,只能你自己用 C 封装一套函数出来。

  • 資深大佬 : ipwx

    @qbqbqbqb #18L:用 int32_t, int64_t 这种

  • 資深大佬 : lovestudykid

    @black11black 大概这样,CC=gcc-10 CXX=g++-10 python setup.py build_ext –inplace,也可以在 script 里设置环境变量。我用这个是因为 Mac 上默认调用 clang 有坑

  • 主 資深大佬 : black11black

    @mckelvin
    @wevsty
    感谢大佬回复,我现在的需求很普通就是有一张从数据库导过来的二维表,这种表结构一般在 python 里是做成表套表,或者表套字典,像这样 [[],[],…] / [{},{},…] 。处理过程放到 cpp 的话确实转换开销蛮高的,所以我理解应该不能进行一些比较细粒度的 c 加速,最好是整个流程完全跑 c,这样只经过一次导入导出转换。

    如果不用 vector 的话怎么处理这种结构呢?我感觉 vector 还是挺合适的,因为 push 添加很轻松,不用考虑内存问题。我现在遇到的问题是,我不会动态向 vector 里添加对象,比如我写在 for 循环中 cdef 一个对象然后 push 进 vector 里,这种语法是不允许的

  • 主 資深大佬 : black11black

    试了一下,似乎在子 block 里新建对象并不需要 cdef 或者 new 之类的( new 在 cython 里似乎没有这个语法),直接 object()就能创建一个对象了。不过我定义结构体后看了一下 cython 生成的分析,似乎修改结构体当中的值仍然需要进行类型校正,似乎这部分是走的 python,并不能起到加速作用。

    代码地址

    https://paste.ubuntu.com/p/s4wk9QfqPB/

    各位大佬指点一下最佳实践是什么,这么做开分析模式看的话感觉还是不太对

  • 主 資深大佬 : black11black

    https://paste.ubuntu.com/p/cBgVXqWQJ8/

    修正,上一代码有小错误

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具