Скорость исполнения Javascript внутри Qt с помощью QJSEngine
Справочная информация: я работаю в проекте, который требует следующего: пользователь может писать команды для выполнения некоторых математических операций с внутренними переменными основной программы (GUI, написанный на Qt/C++).
Мой подход - это текстовое поле, в котором пользователь может писать команды / скрипты на JavaScript, а затем Qt оценивает этот код. Для этого я использую QJSEngine
Проблема: скорость вычисления JavaScript очень плохая / медленная.
Например, у нас есть просто графический интерфейс с двумя текстовыми полями (QTextEdit) и одной кнопкой. В одном текстовом поле пользователь пишет код 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)));
}
1 ответ
Я нашел ответ.
Проблема была в том, что я компилировал его в режиме отладки. В режиме релиза это в 10 раз быстрее.
Измеренное время (с помощью QElapsedTimer), выполняющее его несколько раз:
JavaScript скрипт:
- В режиме отладки: 2900 - 3000 мс
- В режиме выпуска: 255 - 300 мс
То же самое "для" в родном Qt/C++:
- В режиме отладки: 26 - 29 мс
- В режиме выпуска: 7 - 6 мс