【发布时间】:2021-12-29 18:52:03
【问题描述】:
我很难通过 python 的 pybind11 插件系统来利用 C++ 的多线程功能。我知道臭名昭著的 GIL 问题并尝试发布它但无济于事。以下是我的 C++ 代码:
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>
#include "Calculator.h" // where run_calculator is
namespace py = pybind11;
// wrap c++ function with Numpy array IO
int wrapper(const std::string& input_file, py::array_t<double>& in_results) {
if (in_results.ndim() != 2)
throw std::runtime_error("Results should be a 2-D Numpy array");
auto buf = in_results.request();
double* ptr = (double*)buf.ptr;
size_t N = in_results.shape()[0];
size_t M = in_results.shape()[1];
std::vector<std::vector<double> > results;
pybind11::gil_scoped_release release;
run_calculator(input_file, results);
pybind11::gil_scoped_acquire acquire;
size_t pos = 0;
for (size_t i = 0; i < results.size(); i++) {
const std::vector<double>& line_data = results[i];
for (size_t j = 0; j < line_data.size(); j++) {
ptr[pos] = line_data[j];
pos++;
}
}
}
PYBIND11_MODULE(calculator, m) {
// optional module docstring
m.doc() = "pybind11 calculator plugin";
m.def("run_calculator", &wrapper, "Run the calculator");
}
然后在python端:
results= np.zeros((N, M))
start = datetime.datetime.now()
run_calculator(input_file, results)
end = datetime.datetime.now()
elapsed = end - start
print(f'the calculation takes {elapsed.total_seconds()} seconds')
基本上,计算器接受一个文件路径,然后返回一个二维数组。我将这些数据传回给 python。在计算器中,我放置了多线程。
然而,即使有了这个 pybind11::gil_scoped_release 版本,运行时间也没有减少。如果我在C++端运行使用main函数调用run_calculator,多线程的影响是非常明显的。
我也尝试过以这种方式将模块声明为pybind11,而不是使用gil_scoped_release
PYBIND11_MODULE(calculator, m) {
// optional module docstring
m.doc() = "pybind11 calculator plugin";
m.def("run_calculator", &wrapper, py::call_guard<py::gil_scoped_release>());
}
但是运行只是崩溃了。
谁能给我指出正确的方向?
【问题讨论】:
-
你怎么知道?这是一个单一的操作。线程如何在这里为您提供帮助?当然,
run_calculator的运行不会受到 Python 的影响。您的 GIL 版本唯一要做的就是允许其他 Python 线程同时运行。还有什么在运行? -
多线程位于 run_calculator 中。 input_file 有数百行数据,计算器会启动多线程并行处理这些行。我可以看到,如果只运行 C++ 部分,多线程确实会成比例地减少计算器的运行时间,但是使用 pybind11 并使用 python 驱动,实际上并没有减少计算器的运行时间。
-
如果您在
run_calculator中使用多线程,GIL 根本不会影响这一点。 GIL 阻止多个 python 线程一起运行,但它不控制你的 C++ 代码的作用。 -
你是对的。我现在确实看到了 C++ 中的多线程。
标签: python c++ multithreading pybind11 gil