Проблема производительности Python всегда подвергалась критике со стороны разработчиков, но лаконичный синтаксис и быстрое развитие языка Python очень нравятся разработчикам. Как улучшить производительность программ Python всегда было темой для разработчиков Python.
В этой статье описывается способ повышения производительности среды выполнения с помощью расширений C для Python. Самый популярный интерпретатор Python — CPython, написанный на языке C. Поэтому сами языки Python и C имеют хорошую совместимость, а также могут вызывать друг друга.
Далее я расскажу, как использовать Python для вызова программ на C.
Среда этой статьи: mac + Python3. В качестве примера программа использует программу алгоритма Фибоначчи. Пример полного кода:GitHub.com/VP Proposes/Прыжки — Боюсь…
1. Python/C API
Во-первых, представлен самый простой метод, реализованный через Python/C API.
Python extension moduleЭто модуль, который Python официально предоставляет на языках, отличных от Python, и может вызываться Python.Официальный адрес документа:docs.Python.org/3/extending…, рекомендуется всем прочитать его при написании расширений C.
Во-первых, чтобы показать вам, какая версия Python Feibolaqi:
def fib_recursive(n):
if n < 2:
return n
return fib_recursive(n - 1) + fib_recursive(n - 2)
start_ts = time.time()
print(fib_recursive(35))
print(time.time() - start_ts)
# 运行结果:
# 9227465
# 3.8501219749450684
Если эту программу изменить на программу на языке C, названную какspeedup_fib.c, как переписать, необходимо выполнить следующие шаги:
1.1 Импорт Python.h
Python/C API — это среда для установки модуля расширения Python на языке C. Сначала необходимо импортировать файл заголовка Python.h.
// content of speedup_fib.c
#include <Python.h>
long long _fib(long long n){
if(n < 2)
return n;
else
return _fib(n-1) + _fib(n-2);
};
вводитьPython.h, напишите версию Фибоначчи на языке C.
1.2 Функция упаковки
В Python все является объектом, что соответствует языку C.PyObject, поэтому оберните исходную функцию так, чтобы и параметры, и возвращаемые значения былиPyObject.
Чиновник предоставляет три формы параметров:
- (PyObject *self)
- (PyObject *self, PyObject *args)
- (PyObject *self, PyObject *args, PyObject *kwargs)
где args представляют позиционные аргументы, а kwargs — аргументы ключевого слова.
Чтобы преобразовать эти аргументы в Python в параметры языка C, определенные вами, вам нужно вызвать несколько API, за подробностями обратитесь к официальной документации.docs.ython.org/3/from-api/arg...Скриншот ниже.
Обычно используется 2.
- int PyArg_ParseTuple(PyObject *args, const char *format, ...)
- int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char *keywords[], ...)
Первый обрабатывает обычные позиционные аргументы, второй обрабатывает как позиционные аргументы, так и аргументы ключевого слова.
вformatТип параметра формата, например, длинное целое число или строка и т. д. Подробности см. в официальной документации:docs.Python.org/2.0/ext/ боится жары…
Поскольку код Fiobara не имеет ключевого значения параметрам, используется первая функция, и параметры должны быть отформатированы как длительное целое число, а документ запроса длинойlВыражать.
Согласно приведенному выше объяснению, окончательная пакетная процедура выглядит следующим образом:
// content of speedup_fib.c
static PyObject *fib(PyObject *self, PyObject *args) {
long long n; // 定义 参数
long long res; // 定义返回值
// 将参数进行包装,并格式化为长整型l,如果包装失败,则返回NULL.
if (!PyArg_ParseTuple(args, "l", &n))
return NULL;
// 调用C语言版本的斐波拉契,同时传入包装好的参数n
res = _fib(n);
// 将返回值用 Py_BuildValue 包成 PyObject 传给 Python
return Py_BuildValue("l", res);
};
Обернутая функция Фибоначчи определяется какfib, и, наконец, возвращаемое значение также необходимо упаковать, а возвращаемое значение языка C упаковывается вPyObject.
1.3 Объявление списка методов модуля
После того, как функции модуля упакованы одна за другой, необходимо установить список методов модуля. Цель состоит в том, чтобы объявить соответствующую связь между каждой упакованной функцией и функцией языка C, а также форму, в которой передается функция. в. Формат:
{name, method, flags, doc}
即 {名称,包装函数,哪种argument形式, 描述}
Для идентификации флагов обратитесь к официальной документации:docs.Python.org/3/from-api/str…
Есть еще METH_VARARGS и METH_KEYWORDS, соответствующие аргументам и ключевым словам соответственно.
Таким образом, согласно приведенному выше описанию, определенные методы модуля:
// content of speedup_fib.c
static PyMethodDef SpeedupFibMethods[] = {
{"speedup_fib", (PyCFunction) fib, METH_VARARGS, "fast fib"},
{NULL, NULL, 0, NULL} // 以 NULL 作结
};
1.4 Определите структуру модуля
После установки методов модуля вам также необходимо определить структуру модуля, и вам нужна эта информация для создания объекта модуля. Формат:
{base, name, doc, size, module methods 表}
即 {PyModuleDef_HEAD_INIT, 名字, 描述, 分配内存大小, module 方法列表}
Для соответствующих определений, пожалуйста, обратитесь к официальной документации:DOCS.PYTHON.ORG/3/ Из -API/Touch...
В соответствии с приведенным выше описанием определите функцию структуры модуля как:
// content of speedup_fib.c
static struct PyModuleDef speedup_fib_module = {
PyModuleDef_HEAD_INIT,
"speedup_fib",
"A module containing methods with faster fib.",
-1, // global state
SpeedupFibMethods
};
1.5 Определение метода инициализации модуля
Затем определите метод инициализации модуля, целью которого является создание объекта модуля в соответствии с информацией о структуре модуля, и этот объект модуля может быть вызван Python.
Обратите внимание, что метод инициализации модуля должен начинаться с PyInit_.
// content of speedup_fib.c
PyMODINIT_FUNC PyInit_speedup_fib() {
return PyModule_Create(&speedup_fib_module);
}
1.6 Создание модуля расширения
Вышеупомянутые 5 шагов были поставленыspeedup_fib.cРаздел кода закончен, вам нужно создатьsetup.py,пройти черезDistutilsМодули создают модули языка C.
# content of setup.py
from distutils.core import setup, Extension
speedup_fib_module = Extension('speedup_fib', sources=['speedup_fib.c'])
setup(
name='SpeedupFib',
description='A package containing modules for speeding up fib.',
ext_modules=[speedup_fib_module],
)
Сначала укажите, какой метод в какой программе C, а затем вызовите программу установки, чтобы создать файл расширения.
следующей командой:
python3 setup.py build_ext --inplace
создаст файл в текущей папкеspeedup_fib.cpython-37m-darwin.soфайл, который затем может быть вызван непосредственно в Python.
есть тест:
from speedup_fib import speedup_fib
start_ts = time.time()
print(speedup_fib(35))
print(time.time() - start_ts)
# 运行结果:
# 9227465
# 0.054654836654663086
По сравнению с предыдущей программой Python скорость в 80 раз выше, чем больше n, тем больше будет разрыв в скорости.
2. ctypes
Если вы считаете, что первый метод слишком громоздкий, тогда введите ctypes, ctypes — это библиотека, предоставляемая Python, которая позволяет Python входить во внешнюю библиотеку динамической компоновки (DLL) или разделяемую библиотеку для вызова в ней функций.
Таким образом, вам больше не нужно обращать внимание на API, связанные с Python и C, и сосредоточиться на написании функций C.
2.1 Напишите версию программы на языке C
Этот шаг ни в коем случае нельзя пропускать, и первым делом нужно написать версию программы на языке Си.
// content of speedup_fib.c
long long fib(long long n){
if(n < 2)
return n;
else
return fib(n-1) + fib(n-2);
};
Это не очень просто, нужно только сосредоточиться на написании функций, заголовочные файлы даже не нужны.
2.2 Создать общую библиотеку
Для этого шага требуется инструмент gcc, если нет, вам необходимо сначала установить его.
gcc -shared -fPIC speedup_fib.c -o speedup_fib.so
Создайте файл speedup_fib.so из speedup_fib.c с помощью приведенной выше команды.
2.3 Знакомство с библиотекой
Следующий шаг прост, просто нужно улучшить метод ctypes, ввести файл speedup_fib.so, а затем можно запускать Python.
# content of fib.py
from ctypes import *
func = cdll.LoadLibrary('./speedup_fib.so')
start_ts = time.time()
print(func.fib(35))
print(time.time() - start_ts)
Запуск вышеуказанного файла fib.py дает результат:
9227465
0.06056809425354004
3. SWIG
Swig (упрощенная обертка и генератор интерфейса) - это более общий и всеобъемлющий инструмент, который поддерживает Python, Perl, Ruby и другие языки.
Во-первых, вам нужно сначала установить SWIG, если это среда Mac напрямуюbrew install swigПросто ссылка на официальный сайт оконной среды:woohoo.swig.org/doc3.0/pref…
3.1 Создание версии программы на языке C
Этот шаг обязателен, но в swig команда — это заголовочный файл .h.
// content of speedup_fib.h
long long fib(long long n){
if(n < 2)
return n;
else
return fib(n-1) + fib(n-2);
};
3.2 Создать файл интерфейса
Далее создайте интерфейсный файл, который также можно назвать файлом описания интерфейса, принято называть его *.i или *.swg.
Затем определитеspeedup_fib.i
// content of speedup_fib.i
/* 定义 module名称 */
%module speedup_fib
/*导入定义的 speedup_fib.h*/
%{
#include "speedup_fib.h"
%}
/* 告诉 SWIG 定义的 function 或 variable */
long long fib(long long n);
как определено вышеspeedup_fib.i, первый шаг определяет имя модуля, а второй шаг вводит определенныйspeedup_fib.h, который swig будет вызывать функцию внутри, а третий шаг — объявить функцию.
3.3 Создание файла-оболочки
Сгенерируйте speedup_fib.py модуля расширения и speedup_fib_wrap.c файла-оболочки из файла интерфейса через SWIG.
Команда выглядит следующим образом:
swig -python speedup_fib.i
В текущей папке будут еще файлы: spetedup_fib.py и speedup_fib_wrap.c.
3.4 Создать общую библиотеку
На этом шаге создается модуль расширения с API Python/C, используя setup.py и Distutils для создания общей библиотеки:
# content of setup.py
from distutils.core import setup, Extension
# Extension module name 要有底线前缀
speedup_fib_module = Extension('_speedup_fib', sources=['speedup_fib_wrap.c'])
setup(
name='SpeedupFib',
description='A package containing modules for speeding up performance.',
ext_modules=[speedup_fib_module],
)
Обратите внимание, что имя модуля расширения должно начинаться с префикса подчеркивания.
Далее следующая команда:
python3 setup.py build_ext --inplace
создаст файл в текущей папке_speedup_fib.cpython-37m-darwin.soфайл, который затем может быть вызван непосредственно в Python.
# content of fib.py
from speedup_fib import fib
start_ts = time.time()
print(fib(35))
print(time.time() - start_ts)
Запустите Fib.py, результат:
9227465
0.05449485778808594
Эта статья находится здесь, с помощью трех вышеуказанных методов вы можете повысить производительность программ Python с помощью расширений C. Полный кодовый адрес в примере:GitHub.com/VP Proposes/Прыжки — Боюсь…
Для получения дополнительных статей об улучшении производительности программ Python, пожалуйста, подпишитесь на официальный аккаунт: