Español Português
Битва за скорость: QLUA vs MQL5 - почему MQL5 быстрее от 50 до 600 раз?

Битва за скорость: QLUA vs MQL5 - почему MQL5 быстрее от 50 до 600 раз?

MetaTrader 5Примеры | 20 мая 2016, 16:42
3 136 1
MetaQuotes
MetaQuotes

Для сравнения языков MQL5 и QLUA мы написали несколько тестов, которые замеряют скорость выполнения базовых операций. В тестах использовался компьютер с Windows 7 Professional 64 bit, MetaTrader 5 build 1340 и QUIK версии 7.2.0.45.

Результаты представлены в таблице, где все значения представлены в миллисекундах (чем меньше время, тем лучше)

#
Название тестового скрипта
MQL5, ms
 QLUA, ms
Преимущество MQL5
1
 TestFloat 3 969273 39169 раз
2
 TestArrays375230 768615 раз
3
 TestFibo1 12561 11055 раз
4
 TestPiCalculated2 328
183 812
 79 раз
5
 TestQuickSort2 031
211 279
104 раза
 6 TestAckermann 828 64 541 78 раз

Сравнения показывают, что MQL5 быстрее QLUA от 50 до 600 раз на базовых операциях любого языка программирования. Это достигается за счет того, что MQL5 является строго типизированным компилируемым языком в 32/64 бита в противоположность динамическому интерпретируемому QLUA.

Что это дает трейдеру? Возможность максимально быстро обсчитывать огромные массивы данных (а они в MetaTrader 5 практически не ограничены) и быстрее принимать решения.

Это всего лишь проверка базового функционала. Но за фасадом языков скрываются их API. И не у всех он простой. MQL5, будучи прикладным языком для торговой платформы, содержит в себе сотни специализированных функций по доступу/обработке рыночной информации и взаимодействию со всеми компонентами терминала.

Важно, что MQL5 не прицеплен сбоку к существующей системе, а сам является центральным звеном платформы. Все процессы в торговом терминале построены вокруг удовлетворения потребностей разработчиков торговых роботов. Это дает максимальную скорость доступа к внутренним данным платформы и прямой канал для торговых операций.


TestFloat - Скорость выполнения операций с вещественными числами

Код на MQL5

//+------------------------------------------------------------------+
//|                                                    TestFloat.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
//---
#define MAX_SIZE 35000
//---
double f0=0;
double f1=123.456789;
double f2=98765.12345678998765432;
double f3=12345678943.98;
//---
//+------------------------------------------------------------------+
//| Функция OnStart                                                  |
//+------------------------------------------------------------------+
int OnStart()
  {
   uint tick_count,res;
//--- тест
   tick_count=GetTickCount();
   TestFloat();
   res=GetTickCount()-tick_count;
   Print("Test float time=",res," ms");
   Print("Result=",f0);
//--- возвращает время, затраченное на выполнение теста, в милисекундах
   return((int)res);
  }
//+------------------------------------------------------------------+
//| Функция тестирования                                             |
//+------------------------------------------------------------------+
void TestFloat()
  {
   for(int i=0;i<MAX_SIZE;i++)
      for(int j=0;j<MAX_SIZE;j++)
        {
         f0=f0+(f1/(i+1))-f2+(f3*i);
        }
  }
//+------------------------------------------------------------------+

Код на LUA

-- TestFloat
f0=0.0  
f1=123.456789
f2=98765.12345678998765432
f3=12345678943.98
MAX_SIZE=35000
function Start()
   local t=os.clock()
   TestFloat()
   local res=(os.clock()-t)*1000
   -- результы выполнения занесем сюда
   check=f0
   message("TestFloat time=" ..res.." ms\n  check="..tostring(check));
end

function TestFloat()
    -- в цикле мы проходим до значение на 1 меньше, чем MAX_SIZE
        MAX_SIZE=MAX_SIZE-1
        for i=0, MAX_SIZE do
        for j=0, MAX_SIZE do
            f0=f0+(f1/(i+1))-f2+(f3*i);
        end
    end
end
-- запускаем скрипт
Start()

TestArrays - Тестирование времени доступа к элементам массива

Код на MQL5

//+------------------------------------------------------------------+
//|                                                   TestArrays.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
//---
#define MAX_SIZE 32000
//---
int x[MAX_SIZE],y[MAX_SIZE];
//+------------------------------------------------------------------+
//| Функция OnStart                                                  |
//+------------------------------------------------------------------+
int OnStart()
  {
   int  i,k;
   uint tick_count,res;
//--- тест
   tick_count=GetTickCount();
   for(i=0;i<MAX_SIZE;i++)
      x[i]=i+1;

   for(k=0;k<MAX_SIZE;k++)
      for(i=MAX_SIZE-1; i>=0; i--)
         y[i]+=x[i];
   long check=0;
   for(i=0;i<MAX_SIZE;i++)
     {
      check+=y[i];
     }          
   res=GetTickCount()-tick_count;
   Print("TestArrays time=",res," ms");
      Print("check=",check);
//--- возвращает время, затраченное на выполнение теста, в милисекундах
   return((int)res);
  }
//+------------------------------------------------------------------+

Код на LUA

-- TestArrays
function Start()
        MAX_SIZE=32000
    x={}
    y={}
    local start=os.clock()
    for i=1,MAX_SIZE,1 do
      x[i]=i
      y[i]=0
    end  
    y[MAX_SIZE]=0
    for k=1,MAX_SIZE,1 do
        for i=MAX_SIZE, 1,-1 do         
            y[i]=y[i]+x[i]
        end
    end
    local res=(os.clock()-start)*1000
    -- контрольное число
    local check=0
    for k=1,MAX_SIZE,1 do
        check=check+y[k]
    end
    message("Time = "..res.." ms\n  check=".. check)
end
-- запускаем скрипт
Start()


TestFibo - вычисление последовательности ряда Фибоначии

Код на MQL5

//+------------------------------------------------------------------+
//|                                                     TestFibo.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
//---
#define MAX_SIZE 40
long fib[MAX_SIZE];
//+------------------------------------------------------------------+
//| Функция OnStart                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   int  i;
   uint res;
//--- тест
   res=GetTickCount();
   for(i=0;i<MAX_SIZE;i++)
      fib[i]=TestFibo(i);
   res=GetTickCount()-res;
   Print("TestFibo time=",res," ms");
   Print("Fibo[39]=",fib[39]);
  }
//+------------------------------------------------------------------+
//| Функция тестирования                                             |
//+------------------------------------------------------------------+
long TestFibo(long n)
  {
   if(n<2) return(1);
//---
   return(TestFibo(n-2)+TestFibo(n-1));
  }
//+------------------------------------------------------------------+

Код на LUA

-- TestFibo
MAX_SIZE=40
fib={}
function Start()
   start=os.clock()
   for i=0,MAX_SIZE-1 do
     fib[i]=TestFibo(i)
   end
   res=(os.clock()-start)*1000
   message("TestFibo time="..res.." ms\n Fibo[39]="..fib[39])
end

function TestFibo(n)
   if n<2 then
      return(1)
   else
      return(TestFibo(n-2)+TestFibo(n-1))
   end
end
-- запускаем скрипт
Start()



TestPiCalculated -  Вычисление 22 000 знаков числа Pi

Код на MQL5

//+------------------------------------------------------------------+
//|                                             TestPiCalculated.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
//---
#define MAX_SIZE 22000
//--- в эту строку поместим значение числа PI
string str;
int    a[(MAX_SIZE/4+1)*14];
//+------------------------------------------------------------------+
//| Функция OnStart                                                  |
//+------------------------------------------------------------------+
int OnStart()
  {
   uint tick_count,res;
//--- тест
   tick_count=GetTickCount();
   PiCalculate(MAX_SIZE);
   res=GetTickCount()-tick_count;
   Print("TestPiCalculated time=",res," ms");
   Print("Pi=",StringSubstr(str,0,16));
//--- возвращает время, затраченное на выполнение теста, в милисекундах
   return((int)res);
  }
//+------------------------------------------------------------------+
//| Функция тестирования                                             |
//+------------------------------------------------------------------+
void PiCalculate(const int digits)
  {
   int d = 0,e,b,g,r;
   int c = (digits/4+1)*14;
   int f = 10000;
//---
   for(int i=0;i<c;i++)
      a[i]=20000000;
//---
   while((b=c-=14)>0)
     {
      d=e=d%f;
      while(--b>0)
        {
         d = d * b + a[b];
         g = (b << 1) - 1;
         a[b]=(d%g)*f;
         d/=g;
        }
      r=e+d/f;
      if(r<1000)
        {
         if(r>99)
            str+="0";
         else
           {
            if(r>9)
               str+="00";
            else
               str+="000";
           }
        }
      str+=IntegerToString(r);
     }
  }
//+------------------------------------------------------------------+

Код на LUA

-- TestPiCalculated
-- сколько знаков числа Pi будем вычислять
MAX_SIZE=22000
-- в эту строку поместим значение числа Pi
str=""
a={}
function OnStart()
        start=os.clock()
        PiCalculate(MAX_SIZE)
        -- время вычисления числа Pi в миллисекундах
        res=(os.clock()-start)*1000
        message("TestPiCalculated time=" .. res .." ms\n\n Pi="..string.sub(str,1,16)) -- выведем 16 знаков
end
function PiCalculate(digits)
        d = 0
        c = (math.floor(digits/4)+1)*14  -- math.floor() -целочисленное деление на основе примера из справки LUA
        f = 10000

        for i=0,c do
                a[i]=20000000
        end
        c=c-14
        b=c
        while b>0 do
                e=d%f
                d=e
                while b-1>0 do
                        b=b-1
                        d = d * b + a[b]
                        g = (b * 2) - 1
                        a[b]=(d%g)*f  
            d=math.floor(d/g)  -- math.floor(d/g) -целочисленное деление на основе примера из справки LUA
        end
        r=e+math.floor(d/f)  -- math.floor(d/f) - это целочисленное деление на основе примера из справки LUA
                if r<1000 then
                        if(r>99) then 
                                str=str .. "0"
                        else
                                if(r > 9) then
                                        str=str .. "00"
                                else
                                        str=str .. "000"
                                end
                        end
                end
                str=str .. string.format("%d",r)
                c=c-14
                b=c
        end
end
-- запускаем скрипт
OnStart()


Тестирование времени быстрой сортировки массива

Код на MQL5

//+------------------------------------------------------------------+
//|                                                TestQuickSort.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
//--- будем сортировать массив размером в 16 миллионов элементов
#define MAX_SIZE 16000000
//---
int array[MAX_SIZE];
//+------------------------------------------------------------------+
//| Функция OnStart                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   uint tick_count,res;
   for(int i=0;i<MAX_SIZE;i++)
      array[i]=i%100;
   tick_count=GetTickCount();
   QuickSort(array,0,MAX_SIZE-1);
   res=GetTickCount()-tick_count;
   Print("TestQuickSort time=",res," ms");

   for(int i=1;i<MAX_SIZE;i++)
      if(array[i]<array[i-1])
        {
        Print("Array not sorted");
        break;
        }
  }
//+------------------------------------------------------------------+
//| Функция быстрой сортировки                                       |
//+------------------------------------------------------------------+
void QuickSort(int &arr[],int left,int right)
  {
   int i=left;
   int j=right;
   int center=arr[(i+j)/2];
   int x;
//---
   while(i<=j)
     {
      while(arr[i]<center && i<right) i++;
      while(arr[j]>center && j>left) j--;
      if(i<=j)
        {
         x=arr[i];
         arr[i]=arr[j];
         arr[j]=x;
         i++;
         j--;
        }
     }
   if(left<j) QuickSort(arr,left,j);
   if(right>i) QuickSort(arr,i,right);
  }
//+------------------------------------------------------------------+

Код на LUA

-- TestQuickSort
-- будем сортировать массив размером в 16 миллионов элементов
MAX_SIZE=16000000
array={}
function Start()
    for i=0,MAX_SIZE-1 do
        array[i]=i%100
    end
    start=os.clock()
    QuickSort(array,0,MAX_SIZE-1)
    res=(os.clock()-t)*1000
    message("TestQuickSort time=" .. res .. " ms")
    for i=1,MAX_SIZE-1 do
        if array[i]<array[i-1] then
            message("Array not sorted");
            break;
        end
    end
end

function QuickSort(arr,left,right)
    i=left
    j=right
    center=arr[math.floor((i+j)/2)]
    while i<=j do
        while(arr[i]<center and i<right) do
            i=i+1
        end
        while(arr[j]>center and j>left) do
            j=j-1
        end
        if i<=j then
            x=arr[i]
            arr[i]=arr[j]
            arr[j]=x
            i=i+1
            j=j-1
        end
    end
    if left<j then 
        QuickSort(arr,left,j)
    end
    if right>i then 
        QuickSort(arr,i,right)
    end
end
-- запускаем скрипт
Start()


TestAckermann - тестирование рекурсии в функциях

Код на MQL5

//+------------------------------------------------------------------+
//|                                                TestAckermann.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2016, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
//--- количество прогонов функции Аккермана в цикле
#define MAX_SIZE 120000
//+------------------------------------------------------------------+
//| Функция OnStart                                                  |
//+------------------------------------------------------------------+
void  OnStart()
  {
//--- контрольное число
   uint check=0;
//--- время выполнения в миллисекундах
   uint res=0;
//--- тест
   res=GetTickCount();
   for(int i=0;i<MAX_SIZE;i++)
      check+=Ackermann(1+i%3,1+i%5);
   res=GetTickCount()-res;
   Print("TestAckermann time=",res," ms");
   Print("check=",check);
//---
  }
//+------------------------------------------------------------------+
//| Функция тестирования                                             |
//+------------------------------------------------------------------+
int Ackermann(int m,int n)
  {
   if(m==0) return(n+1);
   if(n==0) return(Ackermann(m-1,1));
//---
   return(Ackermann(m-1,Ackermann(m,(n-1))));
  }
//+------------------------------------------------------------------+

Код на LUA

-- TestAckermann
MAX_SIZE=120000
function Start()        
    local check=0 -- контрольное число
    local start=os.clock()
        for i=1,MAX_SIZE do
             check=check+Ackermann(1+i%3,1+i%5);                                                
        end 
    local finish=os.clock()
    local time=(finish-start)*1000
    message("TestAckermann time=".. time.." ms\n\n check="..check)
end

function Ackermann(m,n)
        if(m==0) then return(n+1) end
        if(n==0) then return(Ackermann(m-1,1)) end
        return(Ackermann(m-1,Ackermann(m,(n-1))))
end
-- запускаем скрипт
Start()



Полный архив скриптов можно скачать и проверить результаты самостоятельно.
Прикрепленные файлы |
TestAckermann.mq5 (1.47 KB)
TestArrays.mq5 (2.63 KB)
TestFloat.mq5 (1.53 KB)
TestQuickSort.mq5 (1.89 KB)
Scripts.zip (7.29 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (1)
Sergey Vradiy
Sergey Vradiy | 13 янв. 2018 в 10:04

Так вроде компилируемый код всегда во много раз быстрее интерпретируемого. Или бывают исключения?

Графические интерфейсы VI: Элементы "Чекбокс", "Поле ввода" и их смешанные типы (Глава 1) Графические интерфейсы VI: Элементы "Чекбокс", "Поле ввода" и их смешанные типы (Глава 1)
С этой статьи начинается шестая часть серии о разработке библиотеки для создания графических интерфейсов в терминалах MetaTrader. В первой главе речь пойдёт о таких элементах управления, как «чекбокс», «поле ввода», а также о смешанных типах этих элементов.
Универсальный торговый эксперт: Работа с пользовательскими трейлинг-стопами (часть 6) Универсальный торговый эксперт: Работа с пользовательскими трейлинг-стопами (часть 6)
Шестая часть статьи об универсальном торговом эксперте описывает работу с трейлинг-стопами. Прочитав ее, Вы узнаете, как с помощью унифицированных правил создать свой собственный модуль трейлинг-стопа и подключить его в торговый движок таким образом, чтобы управление позицией с его помощью происходило в автоматическом режиме.
Регулярные выражения для трейдеров Регулярные выражения для трейдеров
Регулярные выражения (англ. regular expressions) — специальный язык для обработки текстов по заданному правилу, которое также называют шаблоном или маской регулярного выражения. В этой статье мы покажем, как обработать торговый отчет с помощью библиотеки RegularExpressions для MQL5, а также продемонстрируем результаты оптимизации с ее использованием.
Графические интерфейсы V: Элемент "Комбинированный список" (Глава 3) Графические интерфейсы V: Элемент "Комбинированный список" (Глава 3)
В первых двух главах пятой части серии о графических интерфейсах были разработаны классы для создания полосы прокрутки и списка. В этой главе рассмотрим класс для создания такого элемента управления, как «Комбинированный список». Это тоже составной элемент, в числе частей которого есть элементы, рассмотренные в первых двух главах пятой части.