python调用C++并突破GIL限制(非多进程)

 python的多线程由于GIL的限制,无法使用多核,如果想使用多核就需要用到多进程,但多进程资源消耗巨大,所以比较合理的方法是在计算密集型任务上使用C/C++来实现构建python模块。

下面的示例利用了pybind11把c++函数封装成python类,然后再使用python来调用模块。

1.C++代码,指定pybind11来绑定C++的函数,这里绑定了thread_task和perform_multithreading两个函数

// example.cpp
#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include <thread>
#include <vector>
#include <iostream>

namespace py = pybind11;

// 一个简单的多线程任务,用于模拟长时间运行的情况
void thread_task(int id, int iterations, py::function callback) {
    // 在这里执行需要关闭 GIL 的多线程任务
    int sum = 1;
    for (int i = i; i < iterations; ++i) {
        // 模拟一些计算或其他密集型任务
        sum=sum*i;
    }
    // 必须获取全局解释器锁才能执行py::function的callback函数
    py::gil_scoped_acquire acquire;
    callback(id, "Thread task completed");
}

void perform_multithreading(int num_threads, int iterations, py::function callback) {
    // 关闭全局解释器锁
    py::gil_scoped_release gil;

    // 创建线程组
    std::vector<std::thread> threads;
    for (int i = 0; i < num_threads; ++i) {
        threads.emplace_back(thread_task, i, iterations, callback);
    }

    // 等待所有线程完成
    for (auto &t : threads) {
        t.join();
    }
}

PYBIND11_MODULE(example, m) {
    m.def("perform_multithreading", &perform_multithreading, "Perform multithreading with GIL released");
    m.def("thread_task",&thread_task,"single task");
}

 2.编写setup.py利用setuptools和pybind11构建模块,这里需要确保你的环境已经安装了pybind11,可以使用”pip install pybind11“来安装。另外如果是windows电脑需要安装visual stido的C+/C++相关的模块(MSVC/C++CL支持/win10sdk等),安装中如果有其它问题请自行查找原因

# setup.py
import setuptools
from setuptools import setup, Extension
import os
import sys
import platform
import pybind11
# 修改为你自己的Pybind11路径
pybind11_path = pybind11.get_include()

# 根据不同平台设置不同的编译参数
extra_compile_args = []
if platform.system() == 'Windows':
    extra_compile_args.append('/std:c++latest')

ext_modules = [
    Extension(
        'example',
        ['example.cpp'],
        include_dirs=[pybind11_path],
        language='c++',
        extra_compile_args=extra_compile_args
    )
]

# 执行setup
setup(
    name='example',
    version='0.0.1',
    author='Your Name',
    description='A simple example of using Pybind11 with Setuptools on Windows',
    ext_modules=ext_modules,
)

 执行下面命令可得到example.so或者example.pyd的动态链接库

python setup.py build develop

 3. 使用测试样例测试效果

# test.py
import example
import time
import threading
from multiprocessing.dummy import Pool

def my_callback(id, message):
    pass
    #print(f"Thread {id} says: {message}\n")

def sum_thread(iterations,call_back):
    tid = threading.current_thread().ident
    example.thread_task(tid,iterations,my_callback)

t0 = time.time()
example.perform_multithreading(100, 5000000, my_callback)
print('C++多线程耗时:',time.time()-t0)



params = [5000000]*100
t0 = time.time()
with Pool(100) as run_pool:
    run_pool.map(lambda x:sum_thread(x,my_callback),params)
print('python多线程耗时:',time.time()-t0)

这里用了C++的多线程和python的多线程计算了100遍4999999!,我们可以看下消耗的时间:

python test.py
C++多线程耗时: 0.015626907348632812
python多线程耗时: 0.11573576927185059

实践证明使用C++多线程关闭GIL,在这个计算型任务上得到了进10倍的加速。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值