Тема: Скорость работы Lua vs С++
Есть мнение, что программа на Си работает быстрее, нежели на Lua.
Мне захотелось проверить насколько код С++ будет производительнее Lua при работе с массивом данных.
Написал тестовый скрипт, считывающий из файла архив графиков (формат взят с Finam) в массив и рассчитывающий по нему SMA ([url=http://rghost.ru/download/private/8KjpCwX8f/53d7ded4efd7acc8c40a239886597a7d/ea306813bfa2c8645b89b89755964005f83a1850/tester.rar]скачать архив с исходниками[/url]):
Calc_SMA.lua
local sScriptPath = getScriptPath()
package.path = sScriptPath..'\\?.lua;'..package.path
require('tester')
function main()
-- Засекаем время:
local nClock = os.clock()
-- Считываем данные из файла и заносим их в массив в памяти в виде свечей (файл данных приложен к архиву):
local sError = tester.CreateCandles(sScriptPath..'\\data.txt')
-- Если функция завершилась с ошибкой, выводим сообщение об ошибке и выходим:
if sError then message(sError, 3) error(sError, 0) end
-- Выводим время работы функции:
message(string.format('Данные прочитаны за %0.3f сек', os.clock()-nClock), 2)
nClock = os.clock()
tester.CreateCandles2(sScriptPath..'\\data.txt')
message(string.format('Данные скопированы за %0.3f сек', os.clock()-nClock), 2)
-- Создаём таблицу, куда будем выводить ход выполнения расчёта индикатора:
hID = AllocTable()
AddColumn(hID, 1, 'Дата', true, QTABLE_DATE_TYPE, 12)
AddColumn(hID, 2, 'Продолжительность', true, QTABLE_TIME_TYPE, 12)
CreateWindow(hID)
SetWindowPos(hID, 0, 0, 161, 60)
InsertRow(hID, -1)
-- Засекаем время:
nClock = os.clock()
-- Расчитываем индикатор и заносим значения в массив
-- Расчёт будет вестись юпо параметру Weighted Close ('W')
-- Дополнительно передаём стартовое время и ID таблицы для вывода хода расчёта
tester.CalcSMA(50, 'W', nClock, hID)
-- Выводим время работы функции:
message(string.format('Индикатор расчитан за %0.3f сек', os.clock()-nClock), 2)
end
tester.lua
-- Заголовок файла с данными свечей:
local sHeader = '<TICKER>,<PER>,<DATE>,<TIME>,<OPEN>,<HIGH>,<LOW>,<CLOSE>,<VOL>'
local io_open, os_time, os_clock, pcall = io.open, os.time, os.clock, pcall
local string_format, string_match = string.format, string.match
local SetCell = SetCell
module('tester')
-- Обявляем массивы для хранения значений индикатора и данных свечей:
local tSMA, tCandles = {}
function CreateCandles(sFileName)
-- Функция чтения файла данных
local hFile, sError = io_open(sFileName, 'r')
if not hFile then return false, sError end
local sLine = hFile:read()
if sLine ~= sHeader then
-- Если заголовок файла неверный - выходим с ошибкой:
sError = 'Неверный заголовок в файле "'..sFileName..'": "'..(sLine or 'nil')..'"'
else
local tData, tPrice, nNum = {}, {}
for sLine in hFile:lines() do
-- Парсим считанную строку:
local Year, Month, Day, Hour, Min, Sec, Open, High, Low, Close, Volume = string_match(sLine, '^.+,[%d]+,(%d%d%d%d)(%d%d)(%d%d),(%d?%d)(%d%d)(%d%d),(%d+%.?%d-),(%d+%.?%d-),(%d+%.?%d-),(%d+%.?%d-),(%d+)')
nNum, Close = (nNum or 0) + 1, Close+0
-- Заносим в массив в виде свечей:
tData[nNum] = {open=Open+0, close=Close, high=High+0, low=Low+0, volume=Volume+0, datetime={year=Year, month=Month, day=Day, hour=Hour, min=Min or '00', sec=Sec or '00'}}
-- Заносим цену закрытия в отдельный массив (использовалось в предыдущей версии, оставил "до кучи"):
tPrice[nNum] = Close
end
tCandles, tData, tPrice = {tData, tPrice}, nil
end
hFile:close() hFile = nil
return sError
end
local function _GetValue(data, sParam)
-- Функция получения значения заданного параметра из массива данных
-- (Close, Open, High, Low, Volume, Median Price, Typical Price, Weighted Close)
if not sParam or sParam == 'C' then return data.close
elseif sParam == 'O' then return data.open
elseif sParam == 'H' then return data.high
elseif sParam == 'L' then return data.low
elseif sParam == 'V' then return data.volume
elseif sParam == 'M' then return (data.high + data.low) / 2
elseif sParam == 'T' then return (data.high + data.low + data.close) / 3
elseif sParam == 'W' then return (data.high + data.low + 2*data.close) / 4
else return data.close end
end
local function SMA(nIndex, nPeriod, tData, sParam)
-- Расчёт среднего значения по заданному периоду
if nIndex < nPeriod then return nil end
local nSum = 0
for i = nIndex-nPeriod+1, nIndex do
nSum = nSum + _GetValue(tData[i], sParam)
end
return nSum / nPeriod
end
function CalcSMA(nPeriod, sParam, nClock, hID)
-- Расчёт простой скользящей средней
local tData, Month = tCandles[1]
for nIndex = 1, #tData do
-- Заносим полученное значение в массив:
tSMA[nIndex] = SMA(nIndex, nPeriod, tData, sParam)
local data = tData[nIndex]
local tTime = data.datetime
local month = tTime.month
-- Выводим ход выполнения расчёта в визуальную таблицу
-- При необходимости функции вывода в таблицу SetCell можно закомментировать
-- Но они не оказывают сколько-нибудь заметного влияния на общую скорость выполнения расчёта
if month ~= Month then -- В таблицу выводится не каждый результат, а только при смене месяца свечных данных
Day, Month, Year = tTime.day, month, tTime.year
-- Выводим текущий месяц, по которому производится расчёт:
SetCell(hID, 1, 1, Day..'.'..Month..'.'..Year, (Year..Month..Day)+0)
local nClock = os_clock()-nClock
-- Выводим продолжительность работы функции:
SetCell(hID, 1, 2, string_format('%0.3f', nClock), nClock)
end
end
end
Но мне сложно это сделать ввиду незнания языка. Может кто-нибудь помочь переписать библиотеку tester на C++?