• [Python] Python 调用 C 共享库


      Linux/Unix 平台下共享库(Shared Library)文件后缀 .so;在 Windows 平台称为动态链接库(Dynamic Link Library),文件名后缀为 .dll。


    利用 ctypes 模块调用 C 共享库

      ctypes 是 Python 标准库提供的一个模块,Python 2.3 版本以上支持该模块。ctypes 是 Python 高级外部函数接口,Python 通过它可以调用 C 语言编译的静态链接库和动态链接库。ctypes 支持多个平台,包括 Windows, Windows CE, Mac OS X, Linux, Solaris, FreeBSD, OpenBSD。

      ctypes 模块定义了一些基础 C 兼容数据类型,具体类型请点击此处查看。

      以下实例演示如何在 Python 程序中使用 ctypes 模块来调用 C 程序函数。

    1. 准备 C 程序源文件 sum.c

      在 sum.c 源文件定义一个 sum() 函数,用以计算 N 个连续自然数之和。

    #include <stdio.h>
    
    int main(void){
        int x;
        printf("Input an integer:
    ");
        scanf("%d", &x);
        printf("sum=%d
    ", sum(x));
        return 0;
    };
    
    int sum(int x){
        int i, result=0;
        for(i=0; i<=x; i++){
            result+=i;
        }
        return result;
    };

    2. 将 C 源代码编译成共享库文件 sum.so

      使用 gcc 编译器将 sum.c 编译为共享库文件 sum.so。

    $ gcc sum.c -fPIC -shared -o sum.so

    3. 准备 Python 模块 sum.py

      在 sum.py 模块中我们定义一个 py_sum() 函数,该函数是 sum.c 文件中 sum() 函数的 Python 实现。

    #!/usr/bin/env python
    # -*- coding: utf8 -*-
    
    import ctypes
    
    so = ctypes.CDLL('./sum.so')
    
    def display_dict():
        print "Type of so is %s" % type(so)
        print "Attributes before calling so.sum: %s" % dir(so)
        print "so.sum(10) = %s" % so.sum(10)
        print "Attributes after calling so.sum: %s" % dir(so)
    
    
    def py_sum(x):
        y = 0
        for i in range(x+1):
            y += i
        return y
    
    
    def so_sum(x):
        return so.sum(x)
    
    
    if __name__ == "__main__":
        pass

      在 Python 模块中 import ctypes,然后通过 ctypes.CDLL() 方法导入共享库文件 sum.so,之后就可以直接调用动态库提供的函数。

      

    4. 测试 Python 调用共享库

      让我们在 __main__ 区块中调用 display_dict 函数:

    if __name__ == "__main__":
        display_dict()

      运行 sum.py 查看结果:

    $ python sum.py
    Type of so is <class 'ctypes.CDLL'>
    Attributes before calling so.sum: ['_FuncPtr', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattr__', '__getattribute__', '__getitem__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_func_flags_', '_func_restype_', '_handle', '_name']
    so.sum(10) = 55
    Attributes after calling so.sum: ['_FuncPtr', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattr__', '__getattribute__', '__getitem__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_func_flags_', '_func_restype_', '_handle', '_name', 'sum']

      从结果可以发现 .so 共享库导入到 .py 模块中得到一个 ctypes.CDLL 对象。调用了 C 函数之后,CDLL 对象会将该函数添加到对象属性中。(在调用 sum 函数之后,CDLL 对象属性列表中才包含了 sum 函数。)

    5. Python 调用共享库的性能

      我们修改一下 sum.py 模块:

    if __name__ == "__main__":
        import timeit
        i = 10000
        print "py_sum(%s) = %s" % (i, py_sum(i))
        print "so_sum(%s) = %s" % (i, so_sum(i))
    
        print timeit.timeit("py_sum(10000)", setup="from __main__ import py_sum", number=1000)
        print timeit.timeit("so_sum(10000)", setup="from __main__ import so_sum", number=1000)

      查看运行结果:

    $ python sum.py
    py_sum(10000) = 50005000
    so_sum(10000) = 50005000
    6.82061600685
    0.158802986145

      以上测试显示,循环叠加 10000 次,执行代码 1000 次,Python 代码耗费了 6.820 秒,C 代码耗费了 0.158 秒,Python 代码耗费时间是 C 代码耗费时间的 42.95 倍。

  • 相关阅读:
    Yii2的View中JS代码添加
    Yii2命名规则
    Yii2 Redis的使用
    win7下php5.6安装redis扩展
    Ubuntu安装cuda
    Ubuntu 安装显卡驱动
    TensorFlow 图片resize方法
    anaconda的kernel对jupyter可见
    cuda和显卡驱动版本
    jupyter修改根目录
  • 原文地址:https://www.cnblogs.com/ifantastic/p/3903446.html
Copyright © 2020-2023  润新知