Freeze/Fail 将函数与 OpenMP 结合使用时 [Pybind11/OpenMP]
Freeze/Fail when using functional with OpenMP [Pybind11/OpenMP]
当我将 Pybind11 与 OpenMP 的 for 循环一起使用时,我遇到了 Pybind11 的功能特性问题。我做了一些研究,我的问题听起来与 2 年前 this Pull Request 中的问题非常相似,但是尽管此 PR 已关闭并且问题似乎已解决,但我仍然遇到这个问题。我创建的代码示例有望更好地解释我的问题:
b.h
#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include <omp.h>
namespace py = pybind11;
class B {
public:
B(int n, const int& initial_value);
void map(const std::function<int(int)> &f);
private:
int n;
int* elements;
};
b.cpp
#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include "b.h"
namespace py = pybind11;
B::B(int n, const int& v)
: n(n) {
elements = new int[n];
#pragma omp parallel for
for (int i = 0; i < n; i++) {
elements[i] = v;
}
}
void B::map(const std::function<int(int)> &f) {
#pragma omp parallel for
for (int i = 0; i < n; i++) {
elements[i] = f(elements[i]);
}
}
PYBIND11_MODULE(m, handle) {
handle.doc() = "Example Module";
py::class_<B>(handle, "B")
.def(py::init<int, int>())
.def("map", &B::map)
;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.4...3.18)
project(example)
find_package(OpenMP)
add_subdirectory(pybind11)
pybind11_add_module(m b.cpp)
if(OpenMP_CXX_FOUND)
target_link_libraries(m PUBLIC OpenMP::OpenMP_CXX)
else()
message( FATAL_ERROR "Your compiler does not support OpenMP" )
endif()
test.py
from build.m import *
def test(i):
return i * 20
b = B(2, 2)
b.map(test)
我基本上有一个数组,我想在其中使用 for 循环将 Python 函数应用于每个元素。我知道这是功能和 OpenMP 的问题,特别是因为在我项目的其他部分我成功地使用了 OpenMP,如果我不使用 OpenMP,功能也能正常工作。
编辑:它在地图功能处冻结,必须终止。我正在使用 Ubuntu 21.10、Python 3.9、GCC 11.2.0、OpenMP 4.5 和最新版本的 pybind11 存储库。
您可能遇到了 OpenMP 的调度程序和 Python 的 GIL (Global Interpreter Lock) 之间的死锁。
我建议将 gdb 附加到您的进程并查看线程的位置以验证问题是否确实存在。
恕我直言,将 Python 函数和 OpenMP 混合在一起是自找麻烦。如果你想要 Python 函数的多线程,你可以使用 multiprocessing.pool.ThreadPool
。但是除非你的函数大部分时间都释放 GIL,否则你不会从多线程中受益。
当我将 Pybind11 与 OpenMP 的 for 循环一起使用时,我遇到了 Pybind11 的功能特性问题。我做了一些研究,我的问题听起来与 2 年前 this Pull Request 中的问题非常相似,但是尽管此 PR 已关闭并且问题似乎已解决,但我仍然遇到这个问题。我创建的代码示例有望更好地解释我的问题:
b.h
#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include <omp.h>
namespace py = pybind11;
class B {
public:
B(int n, const int& initial_value);
void map(const std::function<int(int)> &f);
private:
int n;
int* elements;
};
b.cpp
#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include "b.h"
namespace py = pybind11;
B::B(int n, const int& v)
: n(n) {
elements = new int[n];
#pragma omp parallel for
for (int i = 0; i < n; i++) {
elements[i] = v;
}
}
void B::map(const std::function<int(int)> &f) {
#pragma omp parallel for
for (int i = 0; i < n; i++) {
elements[i] = f(elements[i]);
}
}
PYBIND11_MODULE(m, handle) {
handle.doc() = "Example Module";
py::class_<B>(handle, "B")
.def(py::init<int, int>())
.def("map", &B::map)
;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.4...3.18)
project(example)
find_package(OpenMP)
add_subdirectory(pybind11)
pybind11_add_module(m b.cpp)
if(OpenMP_CXX_FOUND)
target_link_libraries(m PUBLIC OpenMP::OpenMP_CXX)
else()
message( FATAL_ERROR "Your compiler does not support OpenMP" )
endif()
test.py
from build.m import *
def test(i):
return i * 20
b = B(2, 2)
b.map(test)
我基本上有一个数组,我想在其中使用 for 循环将 Python 函数应用于每个元素。我知道这是功能和 OpenMP 的问题,特别是因为在我项目的其他部分我成功地使用了 OpenMP,如果我不使用 OpenMP,功能也能正常工作。
编辑:它在地图功能处冻结,必须终止。我正在使用 Ubuntu 21.10、Python 3.9、GCC 11.2.0、OpenMP 4.5 和最新版本的 pybind11 存储库。
您可能遇到了 OpenMP 的调度程序和 Python 的 GIL (Global Interpreter Lock) 之间的死锁。
我建议将 gdb 附加到您的进程并查看线程的位置以验证问题是否确实存在。
恕我直言,将 Python 函数和 OpenMP 混合在一起是自找麻烦。如果你想要 Python 函数的多线程,你可以使用 multiprocessing.pool.ThreadPool
。但是除非你的函数大部分时间都释放 GIL,否则你不会从多线程中受益。