zoukankan      html  css  js  c++  java
  • pyx文件 生成pyd 文件用于 cython调用

    转于:https://www.2cto.com/kf/201405/304168.html

    1. 初衷

    最近学用python,python不愧是为程序员考虑的编程语言,写起来很快很方便,大大节省开发效率。而且,对于小规模程序,运行效率也不错。前两天写了一篇博文《【总结】学用python写程序》,大大地夸奖了python一番。不过这两天,我就受到“诅咒”了。数据规模稍微大一点,python的执行效率的差劲就体现出来了。这两天写的一个程序,尽管在我所知道的范围内,我做了python语言能做的优化,不过程序依然运行了五个小时之久。想把程序改成c++的,不过开发时间较长,而且未来可能还有改动。所以暂罢。

    上网上查了查python效率的问题。一方面,网上这方面资料不是很多,例如:我们都知道stl里面set是用红黑树实现的,不过python的set怎么实现的,貌似网上没有。这说明用python的人貌似都不关心效率问题。另一方面,据网上资料说,python运行效率比java还慢。我作为c++程序员从前很鄙视java的运行效率,原来python还不如java呢!不过java是虚拟机,python是解释器,为什么python更慢呢?原因在于python更加“面向对象”,python的所有类型都是对象,连最普通的整数变量都是对象,都要在运行的时候才能够确定类型、才能够动态创建......这大大加重了运行时的负担,所以运行效率才这么差。对比之下,同样的程序用cython写,仅仅是声明了变量类型,运行效率就会有35%的提升。

    我从前用过openmp,见从前的博文《简单尝试windows多线程程序》。感觉openmp是神器一个,既方便写程序,又能利用cpu的多个核心,大大提升运行效率。问题是,python中能够使用openmp么?答案是悲观的。python的默认实现是cpython,也就是用c来做的实现,而c的函数大部分都不是线程安全的,为了利用这些函数实现、同时又为了运行时的线程安全,python做了GIL(Global Interpreter Lock)的限制,也就是说,同一段时间内只有一个线程才能够访问python解释器。不过这也使得python上面的并发特别困难。

    不过也不是一点方法都没有,cython现在已经支持了openmp。cython是什么?和python、cpython什么关系?python是脚本语言,cpython是用c来实现的python的解释器,cython是另外一种编程语言,介于python和c之间。实际上cython的设计初衷也是这样,既要利用python快捷的编程速度,又要有c语言的运行效率。cython和python的一个显著区别就是,cython的所有变量都要明确声明变量类型——仅仅这一点,相同的程序,cython的运行效率就要比python的高35%!虽然cython是一种独立的编程语言,不过貌似大家不用他独立的编写程序,而是用它来编写python的c扩展(用c高效实现某些程序,再给python调用)。这几天尝试的,就是在cython上面用openmp,并写成python的c扩展,给python调用。

    2. 环境

    windows7 + 32bit + vistual studio 2008 + python 2.7.3 + eric4,都是默认安装路径。

    3. 安装cython

    官网上下载的Cython-0.20.1,从控制台上切到cython的路径,运行setup.py就一路编译安装下去了,没遇到其他问题。

    在网上看到,很多人在安装的时候遇到很多问题,基本上都是找不到c++编译器,具体表现是提示找不到一个叫“vs....bat”的文件。解决办法通常是安装mingw(gcc在windows下的版本),然后修改一个.cfg文件,指定用这个编译器来build。

    windows安装使用这些偏底层的Python扩展太不爽了,怎么彻底解决 error: Unable to find vcvarsall.bat 呢?
        1.不要按网上说的,安装MinGW,然后在“..python安装路径...Libdistutils”下新建一个文件distutils.cfg,在这文件里面指定编译器为mingw32
           如:
    [build]
    compiler=mingw32

    上面这种方式有问题,我也尝试了一下,是不报上面的那个。error: Unable to find vcvarsall.bat错误了 ,但是有开始报:

    UnicodeDecodeError: 'utf8' codec can't decode byte 0xb0 in position 6: invalid s
    tart byte

    查询一下其他博客人家是这样说的

    百度一下mingw是什么,毕竟不是GCC,又不如VC接windows的地气,编译出来的东西,安装上了也有不好使的时候。
    甚至我遇到MinGW还无法编译greenlet0.4.1,导致greenlet无法源码安装。
    MinGW经常command 'gcc' failed with exit status 1 或者error: unrecognized command line option '-mno-cygwin'。
    即使编译通过了,安装上了,你安装的Python标准库不是由mingw编译的,
    你的扩展包却是mingw编译的,谁也不敢保证完全兼容或者说质量跟得上,
    说不准一些莫名其妙的神经质错误。
    我的安装过程没有遇到问题,看网上的解释,貌似是python2.7的cpython是用vistual studio 2008来编译的,默认找对了编译器,所以没问题了。总之,装上了,没问题。

    看来还是按装VS2010:

    摘抄于:http://blog.csdn.net/darren2015zdc/article/details/54574868    
    1.去下载安装VS2010(08版貌似也行,不过没必要用旧版,指不定哪个库又无法编译),给个地址(百度的云盘 国内应该速度可以) http://pan.baidu.com/share/link?shareid=1609273194&uk=3255422755 然后注意这一步很重要:命令行下执行 SET VS90COMNTOOLS=%VS100COMNTOOLS% 如果你安装的是 2012 版 SET VS90COMNTOOLS=%VS110COMNTOOLS% 如果你安装的是 2013版 SET VS90COMNTOOLS=%VS120COMNTOOLS% 或者更暴力,直接配置系统环境变量 VS90COMNTOOLS指向 %VS你的版本COMNTOOLS% 你还可以更暴力,在“..python安装路径...Libdistutils目录下有个msvc9compiler.py找到243行 toolskey = "VS%0.f0COMNTOOLS" % version 直接改为 toolskey = "VS你的版本COMNTOOLS"(这个就是为什么要配 ”VS90COMNTOOLS“ 的原因,
    因为人家文件名都告诉你了是 Microsoft vc 9的compiler, 代码都写死了要vc9的comntools,就要找这个玩意儿,找不到不干活) 这么做的理由是Python2。
    7 扩展包是可以用08版或者更高的VS编译的,其setup.py(安装脚本)都是去windows系统寻找08版的VS,所以设置VS90的path 如果Python版本小于2.7,强烈建议使用 VS08版,用2010或者更高可能部分扩展不好使。给个例子: http://stackoverflow.com/questions/6551724/how-do-i-point-easy-install-to-vcvarsall-bat 这个例子说明 VS2010不适合Python2.6 2.安装VS后该重启的重启,clean一下之前安装Python扩展失败的残留文件,然后 直接下载 pil pillow greenlet eventlet等源码,解压后python setup.py build发现都可以编译了。
    接下来就换成 python setup.py install安装吧。

    4. 写pyx文件

    pyx文件是python的c扩展文件,代码要符合cython的规范,用什么编辑器写都行。我在eric4上写的,结果它默认用python解释器来进行解释,还提示有bug,“语法错误”。不理会他,本来cython的语法在python里面就不支持。创建TestOMP.pyx文件,并在文件中写代码如下:

     TestOMP.pyx

    from cython.parallel import prange, parallel, threadid
    from libc.stdio cimport printf
     
    def Test():
        cdef int i = 0
        cdef int sum = 0
        for i in prange(1000000, num_threads=2, nogil=True):  
            printf ("%d
    ", i)


    第一句引入了cython中的并行处理模块,尤其是prange。我理解,prange就是“python 'range' of parallel version”,就是并行循环。第二句是引入了c语言中的‘printf’函数。整个文件就定义了一个Test函数。看到,每个变量在使用前都要声明类型。在prange中,有参数‘num_threads’来设定并发数量。nogil表示‘no gil(Global Interpreter Lock)’,想要获得并行,这个参数就要设置。在循环过程中,调用了c的库函数printf,来打印每个整数值。

    5. 写setup.py文件

    pyx文件是python的c扩展文件,代码要符合cython的规范,用什么编辑器写都行。我在eric4上写的,结果它默认用python解释器来进行解释,还提示有bug,“语法错误”。

    上面的pyx文件还仅仅是源代码文件,要想被python调用、要想运行,仅仅写了源代码还是不够的。具体来说,还要转成.c或者.c++的文件,并且再进一步转成.pyd文件。pyd文件才是可以直接使用的文件。为了达到上述目的,就要写一个setup.py脚本,如下:

      setup.py

    #!/usr/bin/python  
    #python version: 2.7.3  
    #Filename: SetupTestOMP.py  
       
    # Run as:    
    #    python setup.py build_ext --inplace    
         
    import sys    
    sys.path.insert(0, "..")    
         
    from distutils.core import setup    
    from distutils.extension import Extension    
    from Cython.Build import cythonize    
    from Cython.Distutils import build_ext  
         
    # ext_module = cythonize("TestOMP.pyx")    
    ext_module = Extension(  
                            "TestOMP",  
                ["TestOMP.pyx"],  
                extra_compile_args=["/openmp"],  
                extra_link_args=["/openmp"],  
                )  
         
    setup(  
        cmdclass = {'build_ext': build_ext},  
            ext_modules = [ext_module],   
    )  

    这个完全是一个python脚本,可以在python解释器下面运行。在控制台下,运行如下命令‘python setup.py build_ext --inplace’,就生成了TestOMP.pyd文件。

    当然,同时还有一些杂七杂八的文件,如‘build’目录下面的‘lib’文件。这都提示着,这是在windows vistual studio环境下。在linux+gcc环境下,就要生成.so文件了,而且“/openmp”的选项就要写成“-fopenmp”

    当然,这里的可以回遇到这样的问题:

    Traceback (most recent call last):
    File "setup.py", line 13, in <module>
    from Cython.Build import cythonize
    ImportError: No module named 'Cython'

    可以执行pip进行安装:pip install Cython

    6.写TestOMP.py

    文件上述两个步骤,相当于把某个python效率瓶颈模块(这之前需要用profile工具来定位)用效率更高的代码写成了python的c扩展形式,接下来,就是要在python代码中调用他们。TestOMP.py就是这个调用的脚本,如下:

      

    from TestOMP import Test   
    Test()  

    这个就很容易了,import并且调用。在控制台下,输入“python TestOMP.py”,运行。

     

  • 相关阅读:
    【BZOJ 2124】【CodeVS 1283】等差子序列
    【BZOJ 1036】【ZJOI 2008】树的统计Count
    【BZOJ 1901】【ZJU 2112】Dynamic Rankings
    【BZOJ 3924】【ZJOI 2015】幻想乡战略游戏
    【BZOJ 4103】【THUSC 2015】异或运算
    【BZOJ 4513】【SDOI 2016】储能表
    【HDU 3622】Bomb Game
    【BZOJ 3166】【HEOI 2013】Alo
    【BZOJ 3530】【SDOI 2014】数数
    【BZOJ 4567】【SCOI 2016】背单词
  • 原文地址:https://www.cnblogs.com/nucdy/p/7736155.html
Copyright © 2011-2022 走看看