使用 QJSEngine 在 Qt 中执行 Javascript 的速度
Posted
技术标签:
【中文标题】使用 QJSEngine 在 Qt 中执行 Javascript 的速度【英文标题】:Speed of Javascript executed inside Qt with QJSEngine 【发布时间】:2016-10-05 07:53:03 【问题描述】:背景: 我正在一个需要以下内容的项目中工作:用户可以编写命令来使用主程序的内部变量(用 Qt/C++ 编写的 GUI)执行一些数学运算。
我的方法是一个文本框,用户可以在其中用 javascript 编写命令/脚本,然后 Qt 评估该代码。为此,我使用QJSEngine
问题: JavaScript 的计算速度很差/很慢。
例如,我们只有一个带有两个文本框 (QTextEdit) 和一个按钮的 GUI。用户在一个文本框中编写 JavaScript 代码,当按下按钮时,它会被计算,结果会出现在另一个文本框中。
作为性能不佳的一个例子,当用户编写这个微不足道的 JavaScript 代码时,计算机会花费大约 3 秒来显示答案:
var X = [];
for (var i=0 ; i < 934600 ; ++i )
X[i] = i;
X[120]
另一方面,如果在 Qt/C++ 中执行相同的操作,它是“瞬时的”:
QVector<double> myVec;
for(int i=0; i < 934600; ++i)
myVec.append(i);
qDebug() << myVec.value(120);
我知道 JavaScript 是解释型语言,但这样的表现正常吗?
这里有一个小的 Qt 示例程序 (pr_Parser) 来显示这个问题。我已经在 Qt Creator 4.0.1 中对此进行了测试。使用 Qt 5.7 MSVC2013 64 位。
谢谢。
pr_parser.pro
QT += core gui qml
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = pr_Parser
TEMPLATE = app
CONFIG += c++11
SOURCES += main.cpp\
CMainWindow.cpp
HEADERS += CMainWindow.h
main.cpp
#include "CMainWindow.h"
#include <QApplication>
int main(int argc, char *argv[])
QApplication a(argc, argv);
CMainWindow w;
w.show();
return a.exec();
CMainWindow.h
#include <QMainWindow>
class QPlainTextEdit;
class CMainWindow : public QMainWindow
Q_OBJECT
public:
CMainWindow(QWidget *parent = 0);
~CMainWindow();
private:
QPlainTextEdit *m_p_myScriptWindow;
QPlainTextEdit *m_p_myResultWindow;
private slots:
void slot_ExecuteScript();
;
CMainWindow.cpp
#include "CMainWindow.h"
#include <QtWidgets>
#include <QJSEngine>
CMainWindow::CMainWindow(QWidget *parent)
: QMainWindow(parent)
QWidget *window = new QWidget(this);
setCentralWidget(window);
QString sampleScript = "var X = [];";
sampleScript.append("for (var i=0 ; i < 934600 ; ++i )X[i]=i;");
sampleScript.append("X[120]");
m_p_myScriptWindow = new QPlainTextEdit(sampleScript, this);
m_p_myResultWindow = new QPlainTextEdit(this);
QPushButton *myButton = new QPushButton("Execute", this);
QVBoxLayout *myLayout = new QVBoxLayout(this);
myLayout->addWidget(m_p_myScriptWindow);
myLayout->addWidget(myButton);
myLayout->addWidget(m_p_myResultWindow);
window->setLayout(myLayout);
connect(myButton, SIGNAL(clicked()), this, SLOT(slot_ExecuteScript()));
CMainWindow::~CMainWindow()
void CMainWindow::slot_ExecuteScript()
QJSEngine myEngine;
QString myScript = m_p_myScriptWindow->toPlainText();
QJSValue myValue = myEngine.evaluate(myScript);
if(myValue.isError())
m_p_myResultWindow->setPlainText(myValue.property("message").toString());
else
m_p_myResultWindow->setPlainText(myValue.toString());
// This code is "instanteneous"
// QVector<double> myVec;
// for(int i=0; i < 934600; ++i) myVec.append(i);
// m_p_myResultWindow->setPlainText(QString::number(myVec.value(120)));
【问题讨论】:
需要注意的是,Qt 的QJSEngine
是为QML 设计的,并不是一个高性能的通用JS 引擎。如果您当前获得的性能还可以,那很好。但是,如果您使用另一个引擎(例如 v8),如果您的函数完成大量工作,您将拥有一个性能更好的系统。如果函数很短,QJSEngine
应该会更快,因为它的开销很小。
谢谢,但我不知道如何使用其他引擎。我见过this,但它声明已被放弃。我打算在 JavaScript 中使用的“命令”只是数组操作(求和、乘法等),数组的值约为 1e6
如果您希望在循环 1e6 元素时获得最佳性能,您可能需要 v8。当然,构建和集成它取决于你,它不会有 Qt 前端,但它并不是真正需要的。见google v8 embedding documentation。
【参考方案1】:
我找到了答案。
问题是我在调试模式下编译它。 在发布模式下快 10 倍。
测量的时间(使用 QElapsedTimer)执行多次:
JavaScript 脚本:
在调试模式下:2900 - 3000 毫秒 在释放模式下:255 - 300 毫秒原生 Qt/C++ 中的相同“for”:
在调试模式下:26 - 29 毫秒 在释放模式下:7 - 6 毫秒【讨论】:
以上是关于使用 QJSEngine 在 Qt 中执行 Javascript 的速度的主要内容,如果未能解决你的问题,请参考以下文章
如何从 Qt 5.12 中的 QJSEngine 获取标准输出?