Скорость Javascript, выполняемого внутри Qt с помощью QJSEngine

#javascript #c #performance #qt #qjsengine

#javascript #c #Производительность #qt #qjsengine

Вопрос:

Предыстория: я работаю над проектом, который требует следующего: пользователь может писать команды для выполнения некоторых математических операций с внутренними переменными основной программы (графический интерфейс, написанный на 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. С 64 битами Qt 5.7 MSVC2013.

Спасибо.

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. Следует отметить, что Qt QJSEngine разработан для использования в QML и не предназначен для высокопроизводительного JS-движка общего назначения. Если производительность, которую вы получаете в данный момент, в порядке, это нормально. Но у вас будет гораздо более эффективная система, если вы используете другой движок, например, v8, если ваши функции выполняют значительный объем работы. Если функции очень короткие, QJSEngine они должны быть быстрее, поскольку у них очень мало накладных расходов.

2. Спасибо, но я не знаю, как использовать другой движок. Я видел это , но в нем указано, что это заброшено. «Команды», которые я намерен использовать в JavaScript, — это просто операции с массивами (суммы, умножения и т. Д.), С массивами около 1e6 значений

3. Если вам нужна наилучшая производительность для перебора элементов 1e6, вам, вероятно, понадобится v8. Конечно, вам решать, как его создать и интегрировать, у него не будет интерфейса Qt, но в этом нет особой необходимости. Смотрите Документацию по встраиванию Google v8 .

Ответ №1:

Я нашел ответ.

Проблема заключалась в том, что я компилировал его в режиме отладки. В режиме выпуска в 10 раз быстрее.

Измеренное время (с QElapsedTimer) выполнения его несколько раз:

Сценарий JavaScript:

  • В режиме отладки: 2900-3000 мс
  • В режиме выпуска: 255-300 мс

То же самое «для» в родном Qt / C :

  • В режиме отладки: 26-29 мс
  • В режиме выпуска: 7 — 6 мс