gpt4 book ai didi

c++ - 通过 Python 控制台对 PythonQt 库进行非锁定调用

转载 作者:搜寻专家 更新时间:2023-10-31 00:40:47 27 4
gpt4 key购买 nike

我的 Qt 应用程序有一个 Qt 图形用户界面(基本上是一些按钮和一个绘制数据的 opengl 上下文)。我还添加了利用 PythonQt 类的脚本能力。这些命令是从 PythonQtScriptingConsole 内部评估的。

我已经明确地创建了包装器类和工厂方法来通过控制台通过当前 python 上下文发送 C++ 调用,但是当从控制台内部运行长任务时,gui 卡住,因为(我认为)事件循环没有被处理.所以第一个解决方案是用计时器处理事件循环,但我认为这既慢又有点愚蠢,所以我不喜欢它。一个

有人给点提示吗? Python 全局解释器锁在这里有问题吗?

最佳答案

是的,GUI 正在卡住,因为对 Python 的长时间调用是通过 UI 线程执行的。为了解决这个问题,我能够继承 QThread 并通过命令模式向 Python 模块发出命令。

在开始使用以下类调用多个 Python 模块之前,请确保通过调用 PyEval_InitThreads() 来初始化 Python 中的线程支持,正如您将在我的 main() 函数中看到的那样。

祝你好运!

int main( int argc, char **argv ) {

QApplication qapp(argc, argv);

PyEval_InitThreads(); // IMPORTANT
PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);

PythonQtObjectPtr module = PythonQt::self()->createUniqueModule();

ThreadedPythonContext context(module);
context.start();

# issue some commands into the module
context.issue("import sys");
context.issue("sys.path.append('C:\\Python27\\Lib\\site-packages')");
context.issue("import time");
context.issue("last = time.localtime().tm_sec");

// Release the global interpreter lock (if it has been created and thread support
// is enabled) and reset the thread state to NULL, returning the previous thread
// state (which is not NULL). If the lock has been created, the current thread must
// have acquired it. (This function is available even when thread support is
// disabled at compile time.)

// give up control of the GIL
PyThreadState *state = PyEval_SaveThread();

return qapp.exec()
}

ThreadedPythonContext.h

#ifndef THREADEDPYTHONCONTEXT_H
#define THREADEDPYTHONCONTEXT_H

#include "PythonQt.h"

#include <QtCore/QMutexLocker>
#include <QtCore/QQueue>
#include <QtCore/QThread>
#include <QtCore/QWaitCondition>

class ThreadedPythonContext : public QThread
{
Q_OBJECT
public:
ThreadedPythonContext(const PythonQtObjectPtr &context) :
QThread(),
_context(context),
_running(true)
{
}

~ThreadedPythonContext() {
_running = false;
wait();
}
void issue(const QString &code) {
_lock.lock();
_commands.enqueue(code);
_lock.unlock();

_CommandQueued.wakeOne();
}

bool isCommandQueueEmpty() {
QMutexLocker lock(&_lock);
return _commands.isEmpty();
}

protected:

QString dequeue() {
QMutexLocker lock(&_lock);
QString cmd( _commands.dequeue() );

return cmd.isEmpty() ? "\n" : cmd;
}

void run() {

QMutex signal;
PyGILState_STATE state;

while(_running) {

// wait to be signaled ...
signal.lock();
_CommandQueued.wait(&signal,1);
signal.unlock();

if ( isCommandQueueEmpty() ) {
continue;
}

while ( !isCommandQueueEmpty() ) {

PythonQtObjectPtr p;
PyObject* dict = NULL;

state = PyGILState_Ensure();

if (PyModule_Check(_context)) {
dict = PyModule_GetDict(_context);
} else if (PyDict_Check(_context)) {
dict = _context;
}

if (dict) {
// this command blocks until the code has completed execution
emit python_busy(true);
p.setNewRef(PyRun_String(dequeue().toLatin1().data(), Py_single_input, dict, dict));
emit python_busy(false);
}

// error in the kernel
if (!p) {
PythonQt::self()->handleError();
}
PyGILState_Release(state);
}
}
}

PythonQtObjectPtr _context;

QMutex _lock;
QQueue<QString> _commands;

QWaitCondition _CommandQueued;
bool _running;

signals:
void python_busy(bool);
};

#endif //THREADEDPYTHONCONTEXT_H

关于c++ - 通过 Python 控制台对 PythonQt 库进行非锁定调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14141699/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com