前言

pybind11 — Seamless operability between C++11 and Python

pybind11 官方文档: https://pybind11.readthedocs.io/en/latest/ .

操作系统:Ubuntu 20.04.4 LTS

参考文档

  1. pybind11 官方文档

安装

1
pip install pybind11

传递 numpy 数组

arr.cpp 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <iostream>
#include <thread>
#include <vector>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
namespace py = pybind11;

// 单个线程执行的运算
void update(unsigned long id, py::array_t<int64_t> x){
auto r = x.mutable_unchecked<1>();
for (int i = 1; i < r.shape(0); i++)
{
if (i % id == 0)
{
r(i) = id;
}
// if (PyErr_CheckSignals() != 0)
// throw py::error_already_set();
}
}

// 利用多线程分配 numpy
void launch(py::array_t<int64_t> x) {
// 计算机 cpu 核心数
unsigned long const hardware_threads = std::thread::hardware_concurrency();
std::cout << "cpus: " << hardware_threads << std::endl;
std::vector<std::thread> threads;
for (unsigned long i = 0; i < hardware_threads; i++)
{
threads.emplace_back(update, i+1, x);
}
for(auto& entry: threads)
entry.join();
}

// 测试设置 int 变量
int bernFlag = 0;
void setBern(int con) {
bernFlag = con;
std::cout << "Bern: " << bernFlag << std::endl;
}

// 测试设置字符串变量
std::string inPath = "../data/FB15K/";
void setInPath(std::string path) {
inPath = std::move(path);
std::cout << "Input Files Path : "
<< inPath << std::endl;
}

// Python 接口
PYBIND11_MODULE(arr, m) {
// 分配类型为 int64 numpy 数组
m.def("assign", [](py::array_t<int64_t> x) {
auto r = x.mutable_unchecked<1>();
for (py::ssize_t i = 0; i < r.shape(0); i++)
r(i) = i;
}, py::arg().noconvert());

// 分配类型为 float32 numpy 数组
m.def("assign", [](py::array_t<float> x) {
auto r = x.mutable_unchecked<1>();
for (py::ssize_t i = 0; i < r.shape(0); i++)
r(i) = i;
}, py::arg().noconvert());

// 利用多线程分配 numpy
m.def("launch", &launch, py::arg().noconvert(),
py::call_guard<py::gil_scoped_release>());

// 测试设置 int 变量
m.def("setBern", &setBern);

// 测试设置字符串变量
m.def("setInPath", &setInPath);
}

test_arr.py 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import numpy as np
import arr as m

def test_from_python():
int64_arr = np.zeros(3, dtype=np.int64)
float32_arr = np.zeros(3, dtype=np.float32)
print(int64_arr)
print(float32_arr)
m.assign(int64_arr)
m.assign(float32_arr)
print(int64_arr)
print(float32_arr)

large = np.zeros(10**8, dtype=np.int64)
print(large.size)
print(large)
m.launch(large)
print(large)

path = "/home/luyanfeng/my_code/temp"
m.setInPath(path)

m.setBern(100)

test_from_python()

编译脚本 compile.sh:

1
c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) arr.cpp -o arr$(python3-config --extension-suffix)

结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(test) luyanfeng@amax:~/my_code/temp$ ls
arr.cpp compile.sh test_arr.py
(test) luyanfeng@amax:~/my_code/temp$ bash compile.sh
/usr/bin/ld: warning: /usr/lib/gcc/x86_64-linux-gnu/7/libstdc++.so: unsupported GNU_PROPERTY_TYPE (5) type: 0xc0010001
/usr/bin/ld: warning: /usr/lib/gcc/x86_64-linux-gnu/7/libstdc++.so: unsupported GNU_PROPERTY_TYPE (5) type: 0xc0010002
(test) luyanfeng@amax:~/my_code/temp$ python test_arr.py
[0 0 0]
[0. 0. 0.]
[0 1 2]
[0. 1. 2.]
100000000
[0 0 0 ... 0 0 0]
cpus: 32
[ 0 1 1 ... 1 23 11]
Input Files Path : /home/luyanfeng/my_code/temp
Bern: 100
(test) luyanfeng@amax:~/my_code/temp$

打包项目

Setuptools Quickstart: https://setuptools.pypa.io/en/latest/userguide/quickstart.html .

pybind11 官方例子: https://github.com/pybind/python_example .

复杂项目例子: https://github.com/LuYF-Lemon-love/pybind11-OpenKE/blob/pybind11-OpenKE-PyTorch/setup.py .

结语

第七十篇博文写完,开心!!!!

今天,也是充满希望的一天。