要解决的问题:
在c++中嵌入python解释器,可以执行python脚本,且可以开启多个c++线程来并行执行python脚本。分别使用python的CAPI和结合pybind11 来使用。
测试环境:
Deepin 15.11 / Ubuntu 16.04
python3.5
如果使用Python CAPI, 代码如下 EmbedPyInCpp.cpp
#include
#include
#include
void Test()
{
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
const char *filename = "Embed.py";
FILE *f;
f = fopen(filename, "r");
PyRun_SimpleFile(f, filename);
// PyObject *pdict = PyDict_New();
// PyObject *pkey = PyBytes_FromString("app");
// PyObject *pvalue = Py_BuildValue("l", 3);
// PyDict_SetItem(pdict, pkey, pvalue);
// long v = PyLong_AsLong(PyDict_GetItem(pdict, pkey));
// printf("value: %d\n", v);
fclose(f);
PyGILState_Release(gstate);
}
struct Interpreter
{
Interpreter()
{
if (initialized)
return;
// initialize Python
Py_Initialize();
// initialize thread support
PyEval_InitThreads();
tstate = PyEval_SaveThread();
initialized = true;
}
~Interpreter()
{
if (finalized)
return;
printf("destructed\n");
PyEval_RestoreThread(tstate);
Py_Finalize();
finalized = true;
}
private:
static PyThreadState *tstate;
static bool initialized;
static bool finalized;
};
bool Interpreter::initialized = false;
bool Interpreter::finalized = false;
PyThreadState *Interpreter::tstate = NULL;
Interpreter interpreter;
int main()
{
std::thread thrd(&Test);
thrd.detach();
std::thread thrd2(&Test);
thrd2.detach();
int i = 10;
while (i >= 0)
{
printf("waiting in main thread, left: %i seconds\n", i);
sleep(1);
i--;
}
}
Makefile
EmbedPyInCpp:EmbedPyInCpp.cpp
g++ `python3-config --includes` `python3-config --ldflags` $< -o $@
.PHONY:clean
clean:
rm -rf EmbedPyInCpp
Embed.py
import os
import time
print("current directory is %s" % os.getcwd())
for i in range(10):
print("current time is %s" % (time.ctime()))
time.sleep(1)
以上是使用python 的 CAPI,如果使用pybind11的话,参考如下代码:
#include
#include
#include
#include
#include
#include "Funcs.h"
namespace py = pybind11;
using namespace py::literals;
void Test(std::shared_ptr
Funcs.h
#pragma oncce
#include
class Math : public std::enable_shared_from_this
{
public:
Math(int i, int j) : i(i), j(j) {}
void show() { printf("i: %i, j: %i, sum: %i\n", i, j, sum()); }
int sum() { return i + j; }
int i{0}, j{0};
};
PyFuncs.cp
#include
#include
#include "Funcs.h"
namespace py = pybind11;
using namespace py::literals;
PYBIND11_MODULE(PyFuncs, m)
{
py::class_>(m, "Math")
.def(py::init())
.def_readwrite("i", &Math::i)
.def_readwrite("j", &Math::j)
.def("sum", &Math::sum)
.def("show", &Math::show);
}
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.12)
project(cmake_example)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Bin)
add_subdirectory(pybind11)
pybind11_add_module(PyFuncs PyFuncs.cpp)
add_executable(TestEmbedPython TestEmbedPython.cpp)
target_link_libraries(TestEmbedPython PRIVATE pybind11::embed pthread)
target_include_directories(TestEmbedPython PRIVATE ${pybind11_INCLUDE_DIR})