1、c++支持线程中调用python函数接口;
2、支持python复杂参数类型如下:字典类型、嵌套列表类型;
支持QMap转python字典类型; QList/QVector转python列表、嵌套列表类型;
3、支持c++/qt多线程调用python函数;
4、python线程锁
5、c++调用shell命令
#include <pybind11/pybind11.h>
#include <pybind11//stl.h>
#include <pybind11/embed.h> // everything needed for embedding
#include "PyThreadStateLock.h"
#include "Python.h"
#include "windows.h"
#include "shellapi.h"
#include "atlstr.h"
一、初始化python
void MyTabWidget::pythonInit()
{
if (!Py_IsInitialized())
{
// char* pwd;
// if ((pwd=_getcwd(NULL, 0)) == NULL) {
// qDebug("getpwd error");
// }
// Py_SetPythonHome((wchar_t*)pwd);
// python包目录
// Py_SetPythonHome((wchar_t*)(L"C:\\Users\\ZZJ\\AppData\\Local\\Programs\\Python\\Python312"));
//调试时用下面绝对路径,正式版本用上面那一行
Py_SetPythonHome((wchar_t*)(L"C:\\Python312"));
Py_Initialize();
if (!Py_IsInitialized()) {
qDebug("Initial Python failed!");
}
else {
PyRun_SimpleString("import sys;sys.path.append('.')");
PyEval_InitThreads();
// 启动子线程前执行,为了释放PyEval_InitThreads获得的全局锁,否则子线程可能无法获取到全局锁。
PyEval_ReleaseThread(PyThreadState_Get());
qDebug("Initial Python Success!");
}
}
}
二、适配于调用python函数的线程锁文件
PyThreadStateLock.h
//将全局解释器锁和线程的相关操作用类封装
#ifndef PYTHREADSTATELOCK_H
#define PYTHREADSTATELOCK_H
#include "Python.h"
class PyThreadStateLock
{
public:
PyThreadStateLock(void)
{
_save = nullptr;
nStatus = 0;
nStatus = PyGILState_Check(); //检测当前线程是否拥有GIL
if (!nStatus)
{
gstate = PyGILState_Ensure(); //如果没有GIL,则申请获取GIL
nStatus = 1;
}
_save = PyEval_SaveThread();
PyEval_RestoreThread(_save);
}
~PyThreadStateLock(void)
{
_save = PyEval_SaveThread();
PyEval_RestoreThread(_save);
if (nStatus)
{
PyGILState_Release(gstate); //释放当前线程的GIL
}
}
private:
PyGILState_STATE gstate;
PyThreadState* _save;
int nStatus;
};
#endif // PYTHREADSTATELOCK_H
三、c++ 线程中调用函数接口
void QueryDataControl::ThreadEventPod5File(QString datPath, QList<RecordReadsNumberParam>& paramlist)
{
class PyThreadStateLock PyThreadLock; //线程锁 线程加载调用python函数 否则崩溃
QString datatime = QDateTime::currentDateTime().toString("yyyyMMddhhmmss");
std::string path = datPath.toStdString();
const char* cStr = path.c_str();
PyObject* pModule = PyImport_ImportModule("write_pod5"); //pointer file python.py
if (!pModule)
{
qDebug() << "Can't open python file!\n";
return;
}
//调用python函数
PyObject* pFun = PyObject_GetAttrString(pModule, "writePod5"); //调用函数
PyObject* pFun2 = PyObject_GetAttrString(pModule, "test5"); //调用函数
PyObject* pFun3 = PyObject_GetAttrString(pModule, "add"); //调用函数
//python 字典类型-----方法一
PyObject* second_arg = Py_BuildValue("{s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:i,s:s,s:s,s:s}","expName", "man", "exp_time", "2015", "flow_cell_id", "man", "flow_cell_product_code", "man",
"protocol_name", "Memob", "protocol_run_id", "man", "sequencing_kit", "man", "sequencer_position", "man",
"sequencer_position_type", "man", "software", "Memob", "sample_rate", 5000, "system_name", "man",
"system_type", "man", "pore_type", "man");
//创建python 字典类型 将QMap转化为python字典类型 方法二
PyObject* pDict = PyDict_New();
QString python_info_path = QCoreApplication::applicationDirPath() + QString("/auroch_win_v0.4/testInfo.txt");
QMap<QString, QString> test_info;
FileRelevance::LoadPythonTestInfo(python_info_path, test_info);
for (auto& pair : test_info.toStdMap())
{
QString key = pair.first;
QString value = pair.second;
const char* name_value = value.toStdString().c_str();
if (key == Trans("实验样本"))
auto h2 = PyDict_SetItemString(pDict, "expName", Py_BuildValue("s", name_value));
else if (key == Trans("实验日期"))
auto h2 = PyDict_SetItemString(pDict, "exp_time", Py_BuildValue("s", datatime.toStdString().c_str()));
else if (key == Trans("实验芯片"))
auto h2 = PyDict_SetItemString(pDict, "flow_cell_id", Py_BuildValue("s", name_value));
else if (key == Trans("实验仪器"))
auto h2 = PyDict_SetItemString(pDict, "protocol_name", Py_BuildValue("s", name_value));
else if (key == Trans("控速酶"))
auto h2 = PyDict_SetItemString(pDict, "sequencing_kit", Py_BuildValue("s", name_value));
else if (key == Trans("缓冲液"))
auto h2 = PyDict_SetItemString(pDict, "sequencer_position", Py_BuildValue("s", name_value));
else if (key == Trans("建库方式"))
auto h2 = PyDict_SetItemString(pDict, "sequencer_position_type", Py_BuildValue("s", name_value));
else if (key == Trans("蛋白"))
auto h2 = PyDict_SetItemString(pDict, "pore_type", Py_BuildValue("s", name_value));
else if (key == Trans("采样率"))
auto h2 = PyDict_SetItemString(pDict, "sample_rate", Py_BuildValue("i", value.toInt()));
else if (key == Trans("算法版本"))
auto h2 = PyDict_SetItemString(pDict, "software", Py_BuildValue("s", name_value));
}
PyDict_SetItemString(pDict, "flow_cell_product_code", Py_BuildValue("s", "Default"));
PyDict_SetItemString(pDict, "protocol_run_id", Py_BuildValue("s", "Default"));
PyDict_SetItemString(pDict, "system_name", Py_BuildValue("s", "Default"));
PyDict_SetItemString(pDict, "system_type", Py_BuildValue("s", "Default"));
//python字典 方法三
auto h1 = PyDict_SetItemString(pDict, "expName", Py_BuildValue("s", "human")); //往字典类型变量中填充数据
auto h2 = PyDict_SetItemString(pDict, "exp_time", Py_BuildValue("s", "20240515160132")); //往字典类型变量中填充数据
PyDict_SetItemString(pDict, "flow_cell_id", Py_BuildValue("s", "human"));
PyDict_SetItemString(pDict, "flow_cell_product_code", Py_BuildValue("s", "human"));
PyDict_SetItemString(pDict, "protocol_name", Py_BuildValue("s", "human"));
PyDict_SetItemString(pDict, "protocol_run_id", Py_BuildValue("s", "010302"));
PyDict_SetItemString(pDict, "sequencing_kit", Py_BuildValue("s", "human"));
PyDict_SetItemString(pDict, "sequencer_position", Py_BuildValue("s", "human"));
PyDict_SetItemString(pDict, "sequencer_position_type", Py_BuildValue("s", "human"));
PyDict_SetItemString(pDict, "software", Py_BuildValue("s", "human"));
PyDict_SetItemString(pDict, "sample_rate", Py_BuildValue("i", 4000));
PyDict_SetItemString(pDict, "system_name", Py_BuildValue("s", "human"));
PyDict_SetItemString(pDict, "system_type", Py_BuildValue("s", "human"));
PyDict_SetItemString(pDict, "pore_type", Py_BuildValue("s", "human"));
//python 嵌套列表类型
PyObject* first_arg = Py_BuildValue("[[[d,d,d,d,d],i,i,d,s]]",1.2,2.6,3.8,9.6,15.99, 2,2,0.6,"hyh");
if (pFun3)
{
//创建一个元祖
PyObject* pArgs = PyTuple_New(2); //设置参数,用python元组
PyObject* arg1 = Py_BuildValue("i", 5); //设置参数,用python元组
PyObject* arg2 = Py_BuildValue("i", 6); //设置参数,用python元组
auto hyh = PyTuple_SetItem(pArgs, 0, arg1); //i表示创建int型变量
auto hyh2 = PyTuple_SetItem(pArgs, 1, arg2); //i表示创建int型变量
PyObject* pResule = PyObject_CallObject(pFun3, pArgs);
auto resultValue = PyLong_AsLong(pResule);
QString hyhy;
}
if (pFun2)
{
PyObject* args = PyTuple_New(1);
auto h3 = PyTuple_SetItem(args, 0, pDict); //0---序号 将字典类型变量添加到参数元组中
//auto h = PyTuple_SetItem(args, 0, second_arg);
//PyObject* pResule = PyObject_CallObject(pFun2, args);
//if (pResule)
//{
// //处理返回值:
// int size = PyDict_Size(pResule);
// PyObject* pNewAge = PyDict_GetItemString(pResule, "sample_rate");
// PyObject* pNewAge1 = PyDict_GetItemString(pResule, "expName");
// PyObject* pNewAge2 = PyDict_GetItemString(pResule, "exp_time");
// int test;
// char* name;
// char* time;
// PyArg_Parse(pNewAge, "i", &test);
// PyArg_Parse(pNewAge1, "s", &name);
// PyArg_Parse(pNewAge2, "s", &time);
// QString str_name(name);
// QString str_time(time);
//}
//QList<float> datas;
//datas.append(0.56);
//datas.append(10.56);
//datas.append(20.56);
//datas.append(30.56);
//datas.append(120.56);
//datas.append(20.56);
//PyObject* pList1 = PyList_New(datas.size()); // 创建一个长度为3的列表
//for (int i = 0; i < datas.size(); i++)
//{
// PyList_SetItem(pList1, i, PyFloat_FromDouble(datas.at(i))); // 在索引1处插入浮点值3.14
//}
//PyObject* pList = PyList_New(5); // 创建一个长度为4的列表
//PyList_SetItem(pList, 0, pList1);
//PyList_SetItem(pList, 1, PyLong_FromLong(10));
//PyList_SetItem(pList, 2, PyLong_FromLong(20));
//PyList_SetItem(pList, 3, PyFloat_FromDouble(2.68));
//PyList_SetItem(pList, 4, PyUnicode_FromString("hyh"));
//PyObject* args = PyTuple_Pack(1, pList); // 将列表打包为参数元组
//嵌套列表
PyObject* output_args_list = PyList_New(paramlist.size());
;
for (int k = 0; k < paramlist.size(); k++)
{
auto param = paramlist.at(k);
PyObject* pList1 = PyList_New(param.datas.size()); // 创建一个长度为3的列表
for (int i = 0; i < param.datas.size(); i++)
{
PyList_SetItem(pList1, i, PyFloat_FromDouble(param.datas.at(i))); // 在索引1处插入浮点值3.14
}
PyObject* pList = PyList_New(5); // 创建一个长度为4的列表
PyList_SetItem(pList, 0, pList1);
PyList_SetItem(pList, 1, PyLong_FromLong(param.channel));
PyList_SetItem(pList, 2, PyLong_FromLong(param.eventId));
PyList_SetItem(pList, 3, PyFloat_FromDouble(param.begin_time));
PyList_SetItem(pList, 4, PyUnicode_FromString("hyh"));
PyList_SetItem(output_args_list, k, pList);
}
PyObject* args_list = PyTuple_Pack(1, output_args_list); // 将列表打包为参数元组
PyObject* pResule = PyObject_CallObject(pFun2, args_list);
}
if (pFun)
{
//创建python列表 嵌套列表
//PyObject* hyh_arge = Py_BuildValue("[[[d,d,d,d,d],i,i,d,s],[[d,d,d,d,d],i,i,d,s]]", 1.2, 2.6, 3.8, 9.6, 15.99, 2, 3, 0.6, "hyh", 1.2, 2.6, 3.8, 9.6, 15.99, 2, 3, 0.6, "hyh");
//QList 自定义结构体类型
PyObject* output_args_list = PyList_New(paramlist.size());
for (int k = 0; k < paramlist.size(); k++)
{
auto param = paramlist.at(k);
PyObject* pList1 = PyList_New(param.datas.size()); // 创建一个长度为3的列表
for (int i = 0; i < param.datas.size(); i++)
{
PyList_SetItem(pList1, i, PyFloat_FromDouble(param.datas.at(i))); // 在索引1处插入浮点值3.14
}
PyObject* pList = PyList_New(5); // 创建一个长度为4的列表
PyList_SetItem(pList, 0, pList1);
PyList_SetItem(pList, 1, PyLong_FromLong(param.channel));
PyList_SetItem(pList, 2, PyLong_FromLong(param.eventId));
PyList_SetItem(pList, 3, PyFloat_FromDouble(param.begin_time));
PyList_SetItem(pList, 4, PyUnicode_FromString("hyh"));
PyList_SetItem(output_args_list, k, pList);
}
单个结构体类型
//auto param = paramlist[0];
//PyObject* pList1 = PyList_New(param.datas.size()); // 创建一个长度为3的列表
//for (int i = 0; i < param.datas.size(); i++)
//{
// PyList_SetItem(pList1, i, PyFloat_FromDouble(param.datas.at(i))); // 在索引1处插入浮点值3.14
//}
//PyObject* pList = PyList_New(5); // 创建一个长度为4的列表
//PyList_SetItem(pList, 0, pList1);
//PyList_SetItem(pList, 1, PyLong_FromLong(param.channel));
//PyList_SetItem(pList, 2, PyLong_FromLong(param.eventId));
//PyList_SetItem(pList, 3, PyFloat_FromDouble(param.begin_time));
//PyList_SetItem(pList, 4, PyUnicode_FromString("hyh"));
//PyObject* args_list = PyTuple_Pack(1, pList); // 将列表打包为参数元组
PyObject* pArgs = PyTuple_New(3);
auto h = PyTuple_SetItem(pArgs, 0, output_args_list);
auto h2 = PyTuple_SetItem(pArgs, 1, pDict);
auto h3 = PyTuple_SetItem(pArgs, 2, Py_BuildValue("s", cStr));
PyObject* pResule = PyObject_CallObject(pFun, pArgs);
if (pResule)
{
char* tse;
PyArg_Parse(pResule, "s", &tse);
QString srt1(tse);
}
PyObject_CallFunction(pFun, NULL); //解决线程崩溃情况
}
}
四、c++调用shell命令
void QueryDataControl::startDorado()
{
LPCWSTR filePath = L"./dorado-0.3.4-win64/bin";
CString strPath;
GetModuleFileName(NULL, strPath.GetBufferSetLength(MAX_PATH + 1), MAX_PATH + 1);
int pos = strPath.ReverseFind('\\');
strPath = strPath.Left(pos + 1);
auto dorado_path = strPath + "dorado-0.3.4-win64\\bin\\dorado.exe basecaller ";
auto dorado_model = strPath + "dorado-0.3.4-win64\\model ";
auto pod5_path = strPath + "Pod5\\ --emit-fastq>";
auto fastq_path = strPath + "fastq\\test\\";
auto fastq_file_str = QDateTime::currentDateTime().toString("yyyyMMddhhmmss") + ".fastq";
std::string str = fastq_file_str.toStdString(); // 将QString转换为std::string
CString fastq_file(str.c_str()); // 将std::string转换为CString
auto cmd_str = dorado_path + dorado_model + pod5_path + fastq_path + fastq_file;
QString m_fast_path_save = QCoreApplication::applicationDirPath() + QString("/fastq/test/")+ QString::fromStdString(str);
m_save_fastqs.append(m_fast_path_save);
wchar_t commandLine[MAX_PATH * 2];
swprintf(commandLine, MAX_PATH * 2, L"/K \"%s\"", cmd_str);
HINSTANCE hNewExe = ShellExecute(NULL, L"open", L"cmd.exe", commandLine, filePath, SW_SHOWNORMAL/*SW_HIDE*/);
}
void QueryDataControl::startAuroch()
{
wchar_t currentDirectory[MAX_PATH];
GetCurrentDirectory(MAX_PATH, currentDirectory); //D:\home_work_new\MeMob96_Code_20230911\MeMob
CString strPath;
GetModuleFileName(NULL, strPath.GetBufferSetLength(MAX_PATH + 1), MAX_PATH + 1);
int pos = strPath.ReverseFind('\\');
strPath = strPath.Left(pos + 1);
wchar_t aurochDirectory[MAX_PATH];
swprintf(aurochDirectory, MAX_PATH, L"%sauroch_win_v0.4", strPath);
wchar_t commandLine[MAX_PATH * 2];
swprintf(commandLine, MAX_PATH * 2, L"/K cd /d \"%s\" && powershell -File auroch_v0.4.ps1 config.ps1", aurochDirectory);
ShellExecute(NULL, L"runas", L"cmd.exe", commandLine, NULL, SW_SHOWNORMAL);
}