微信关注,获取更多

超越Python性能极限:创建C++扩展模块

你是否曾想过如何提高Python代码的性能?或者你是否在处理大规模数据时感到Python的速度有些慢?如果是的话,那么你来对地方了!在本篇文章中,我将带你走进C++的魔幻世界,教你如何创建C++扩展模块,以实现超越Python性能的目标。不要担心,即使你不是C++专家,我也将为你详细解释每一步。

前提条件

在开始之前,确保你已经安装了Visual Studio 2017或更新版本,同时安装了Python开发工作负载。这个工作负载包括Python本地开发工具,这对于创建本地扩展模块是必要的。如果你已经在使用Python,也确保在高级选项下选择了下载调试符号,以便进行Python代码和本地代码的混合模式调试。

创建Python应用程序

首先,我们将创建一个Python应用程序,这将是我们要扩展的Python代码。在Visual Studio中,选择文件 > 新建 > 项目。

搜索Python,选择Python应用程序模板,输入名称和位置,然后点击确定。

在项目的.py文件中,粘贴以下代码,这段代码会计算双曲正切,我们将在后面的步骤中加速它。

from random import random
from time import perf_counter

COUNT = 500000

DATA = [(random() - 0.5) * 3 for _ in range(COUNT)]

e = 2.7182818284590452353602874713527

def sinh(x):
    return (1 - (e ** (-2 * x))) / (2 * (e ** -x))

def cosh(x):
    return (1 + (e ** (-2 * x))) / (2 * (e ** -x))

def tanh(x):
    tanh_x = sinh(x) / cosh(x)
    return tanh_x

def test(fn, name):
    start = perf_counter()
    result = fn(DATA)
    duration = perf_counter() - start
    print('{} took {:.3f} seconds\n\n'.format(name, duration))

if __name__ == "__main__":
    print('Running benchmarks with COUNT = {}'.format(COUNT))

    test(lambda d: [tanh(x) for x in d], '[tanh(x) for x in d] (Python implementation)')

通过调整COUNT变量,你可以改变基准测试的运行时间。现在,选择调试 > 以不带调试启动,来运行这个程序。

创建核心C++项目

接下来,我们将创建两个C++项目,分别是superfastcode和superfastcode2,用于扩展Python。

  1. 在解决方案资源管理器中,右键单击解决方案,然后选择添加 > 新建项目。这样,一个Visual Studio解决方案可以同时包含Python和C++项目。

  2. 搜索C++,选择空项目模板,为第一个项目命名superfastcode,然后点击确定。

  3. 创建一个C++文件,右键点击Source Files节点,选择添加 > 新项。选择C++文件,命名为module.cpp,然后点击确定。

  4. 在主工具栏上,使用下拉菜单选择以下配置之一:

    • 对于64位Python运行时,激活x64配置。
    • 对于32位Python运行时,激活Win32配置。
  5. 在解决方案资源管理器中,右键单击C++项目,选择属性,然后按照以下表格中的设置进行配置:

    选项卡 属性
    General 目标名称 指定模块的名称,以便在Python中引用。如果要使用项目名称作为模块名称,请保留默认值$。对于python_d.exe,添加_d以结束名称。
    Advanced > Target File Extension .pyd
    Project Defaults > Configuration Type Dynamic Library (.dll)
    C/C++ > General 附加包含目录 根据你的安装情况添加Python包含目录(例如,c:\Python36\include)。
    C/C++ > Preprocessor 预处理器定义 如果存在,请将_DEBUG值更改为NDEBUG,以匹配CPython的非调试版本。当使用python_d.exe时,保持此值不变。
    C/C++ > Code Generation 运行时库 选择多线程DLL(/MD)以匹配CPython的非调试版本。当使用python_d.exe时,保持此值为多线程调试DLL(/MDd)。
    Basic Runtime Checks 默认
    Linker > General 附加库目录 添加包含.lib文件的Python libs文件夹,根据你的安装情况(例如,c:\Python36\libs)。确保指向包含.lib文件的libs文件夹,而不是包含.py文件的Lib文件夹。
  6. 构建C++项目以确认代码正确。

  7. 如果尚未完成,重复上述步骤创建第二个项目,命名

为superfastcode2。这个项目将在后面的示例中使用。

编写Python扩展模块

我们已经有了一个C++项目,现在让我们开始编写Python扩展模块。

  1. 在superfastcode项目中,打开module.cpp文件,然后将以下代码添加到文件顶部:
#include <Python.h>

这会包括Python头文件,以便在C++代码中使用Python API。

  1. 在文件中,添加以下C++函数,这些函数将成为Python模块的接口:
static PyObject* superfastcode_tanh(PyObject* self, PyObject* args)
{
    // Parse the input arguments
    PyObject* data;
    if (!PyArg_ParseTuple(args, "O", &data))
    {
        PyErr_SetString(PyExc_TypeError, "Invalid input");
        return NULL;
    }

    // Ensure data is a list
    if (!PyList_Check(data))
    {
        PyErr_SetString(PyExc_TypeError, "Input must be a list");
        return NULL;
    }

    // Iterate through the list and apply tanh function
    PyObject* result = PyList_New(0); // Create an empty list
    if (result != NULL)
    {
        Py_ssize_t size = PyList_Size(data);
        for (Py_ssize_t i = 0; i < size; ++i)
        {
            PyObject* item = PyList_GetItem(data, i);
            double x = PyFloat_AsDouble(item);
            if (!PyErr_Occurred())
            {
                double tanh_x = tanh(x);
                PyObject* tanh_item = PyFloat_FromDouble(tanh_x);
                if (tanh_item != NULL)
                {
                    PyList_Append(result, tanh_item);
                    Py_DECREF(tanh_item);
                }
                else
                {
                    PyErr_SetString(PyExc_RuntimeError, "Failed to create float object");
                    Py_DECREF(result);
                    return NULL;
                }
            }
            else
            {
                PyErr_SetString(PyExc_TypeError, "Invalid item in the input list");
                Py_DECREF(result);
                return NULL;
            }
        }
    }

    return result;
}

static PyMethodDef superfastcode_methods[] =
{
    {"tanh", superfastcode_tanh, METH_VARARGS, "Calculate the hyperbolic tangent of a list of numbers."},
    {NULL, NULL, 0, NULL}
};

static struct PyModuleDef superfastcode_module =
{
    PyModuleDef_HEAD_INIT,
    "superfastcode",
    NULL,
    -1,
    superfastcode_methods
};

PyMODINIT_FUNC PyInit_superfastcode(void)
{
    return PyModule_Create(&superfastcode_module);
}

这些代码定义了一个名为superfastcode的Python模块,其中包括一个名为tanh的函数。这个函数将接受一个Python列表作为输入,计算列表中每个数字的双曲正切,并返回一个包含结果的新列表。

  1. 构建superfastcode项目以生成扩展模块。

使用Python中的扩展模块

现在,我们已经创建了一个C++扩展模块,让我们看看如何在Python中使用它。

  1. 在Python中,创建一个新的.py文件,例如test_superfastcode.py,并添加以下代码:
import superfastcode

data = [0.5, 0.6, 0.7, 0.8, 0.9]
result = superfastcode.tanh(data)
print(result)

这个Python脚本导入了我们的superfastcode模块,并使用其中的tanh函数来计算输入列表的双曲正切。

  1. 运行test_superfastcode.py文件,你将看到计算结果。

结论

通过创建C++扩展模块,我们可以将高性能的C++代码与Python集成在一起,实现更快的计算速度。这对于需要处理大量数据或需要高性能计算的应用程序特别有用。希望本文对你有所帮助,让你更好地理解如何创建和使用Python扩展模块。如果你对此有任何疑问或需要进一步的帮助,请随时提问!

未经允许不得转载:大神网 » 超越Python性能极限:创建C++扩展模块

相关推荐

    暂无内容!