ANTI_Finsov
ANTI_Finsov личный блог
18 февраля 2019, 12:59

Загрузка процессора на 100% от запущенного скрипта lua. Что делать?...

Коллеги, Всем добрый день!

Раньше не приходилось работать с lua.  Но здесь накатал небольшой скрипт в рамках которого происходит запросы текущей цены инструмента и запись её файл и столкнулся с проблемами производительности.
До запуска скрипта  доля нагрузки Quik-a на процессор составляла порядка 2%.
После запуска скрипта нагрузка на процессор увеличилась до 30%.   На рабочем компьютере все работает, но вот на виртуалке, где производительность ниже, всё виснет.
Ребят кто сталкивался с подобным и возможно ли оптимизация данной ситуации?

Скрипт скрипта прилагаю, но не думаю, что в нём проблема:

local stopped=false
local FileNameRead=getScriptPath().."\\poz.txt"
local FileNameWrite=getScriptPath().."\\data.txt"
local FileRead
local ID
local code
FileRead=io.open(FileNameRead,«r»)
local Read
code,ID=FileRead:read(4,"*n")
FileRead:close()
--message(code)
local ID_back=ID
local direct

function OnStop()
stopped=true
return 5000
end


function main()

local TableSI=AllocTable()
AddColumn(TableSI,1,«Дата»,true,QTABLE_DATE_TYPE,10)
AddColumn(TableSI,2,«Время»,true,QTABLE_TIME_TYPE,10)
AddColumn(TableSI,3,«Код»,true,QTABLE_STRING_TYPE,10)
AddColumn(TableSI,4,«Цена»,true,QTABLE_INT_TYPE,10)
AddColumn(TableSI,5,«Позиция»,true,QTABLE_INT_TYPE,10)

while stopped==false do
local ServerTime=tostring(getInfoParam(«SERVERTIME»))
local TradeDate=tostring(getInfoParam(«TRADEDATE»))
local SecCode=«SiH9»
local LastPrice = getParamEx(«SPBFUT», SecCode, «LAST»).param_value
local Pos=getFuturesHolding(«SPBFUT»,«SPBFUT00d8u»,SecCode,0)
if Pos~=nil then
Pos=Pos.totalnet
else
Pos=0
end
FileRead=io.open(FileNameRead,«r»)
local Read
code,ID,Read=FileRead:read(4,"*n","*n")
FileRead:close()
if(Read~=nil) then
if ID_back~=ID then
local Price
if (Read>0) then
Price=tonumber(LastPrice-LastPrice%1)*(-1)*Read
direct=1
elseif (Read<0) then
Price=tonumber(LastPrice-LastPrice%1)*math.abs(Read)
direct=-1
end
local FileWrite=io.open(FileNameWrite,«a»)
if Price~=nil then
FileWrite:write(tostring(Price).." ")
FileWrite:close()
end
sleep(1000)
ID_back=ID
end

end
end
message(«Скрипт остановлен»)
end

 

33 Комментария
  • Jame Bonds
    18 февраля 2019, 13:11
    У вас похоже sleep не там стоит. Поставьте его перед end, завершающем «while stoped»
    А если это по задумке, то поставьте там хотя бы sleep( 0 ), это капитально снизит нагрузку на процессор.
    Если sleep в цикле функции main не выполняется, то скрипт будет полностью съедать одно ядро процессора.
  • bocha
    18 февраля 2019, 13:14
    Работа с файлом в Мэйн в каждом цикле? Экспэнсив!
      • bocha
        18 февраля 2019, 13:22
        ANTI_Finsov, ну мэйн же просто крутится в безусловном цикле с задержкой. Сильно рачительные люди его стараются не нагружать, а условно инициированные действия совершать по колбэкам, ну или хотя бы по If через изменение Global
        Попробуйте поэкспериментировать в этом направлении, должно помочь
      • Андрей К
        18 февраля 2019, 13:25
        ANTI_Finsov, 
        получается в этом проблема?
        а чего гадать, закомментируете, да посмотрите
  • Тихий омут
    18 февраля 2019, 15:01
    смирись… LUA машина кушает один поток и все.
  • Сергей Симонов
    18 февраля 2019, 16:23
    самый тупой и простой метод отладки:

    1. последовательно комментите функции и прогоняете скрипт.
    2. смотрите, какая функция вызывает загруз проца
    3. чешете репу
    4. пишите на СЛ вопрос, если расчесали до крови, а толку — ноль
      • Igr
        19 февраля 2019, 09:33
        ANTI_Finsov, но функция запускается в main? или как?
          • Igr
            19 февраля 2019, 10:46

            ANTI_Finsov, а есть разница разве? она ж всё равно запускается а значит и всё что в этой функуции прописано запускается тоже

             

              • Igr
                19 февраля 2019, 12:33
                ANTI_Finsov, ну у вас же sleep был в этой функции, а теперь вы его вынесли за функцию, в этом была проблема по моему 
          • Igr
            19 февраля 2019, 10:59

            ANTI_Finsov, по моему не в этом ошибка, у вас sleep(1000) был после if, т.е возможно срабатывал только иногда, а когда нет то получается sleep(1000) вообще не работал, а значит main() выполнялся с частотой раз в миллисекунду  

            мне так кажется, вот и загружал комп по полной 

  • Prophetic
    18 февраля 2019, 17:39
    Первое правило скриптов QLua: 
    Функция Main() ВСЕГДА должна выглядеть примерно так:

    function main()
       while running do
          sleep(Freq)
       end
    end

    где Freq — задержка в миллисекундах.

    В зависимости от конкретных задач работа скрипта строится или на вызове определенных функций колбэками или на бесконечном цикле, определенном вне main(). В ряде случаев работа через колбэки может приводить к очень большой нагрузке на процессор, и сопровождаться значительной потерей производительности терминала.

    Если и когда захотите одновременно запускать пару десятков скриптов (торговых роботов) — быстро поймете, что QLua Вам уже не подходит. Да и гибкости часто не хватает.
    Если есть возможность — лучше сразу начинайте смотреть в сторону C#.

    Да, совсем забыл!!!
    quik2dde.ru/index.php

    Это на тот случай, если все же хотите продолжить поглубже изучать QLua.

    • Igr
      19 февраля 2019, 09:32

      Prophetic, а где делать все вычисления если не в main? 

      в колбеках же всё должно быть по минимуму, чисто брать инфу, значения переменных

      • Prophetic
        19 февраля 2019, 09:58
        Igr, В идеале — в отдельных функциях, которые вызываются колбэками.
        Проблема обычно в том, что тот же колбэк «OnAllTrade», по которому мы определяем изменение цены последней сделки по интересующему нас инструменту, вызывается слишком часто, и при сложной логике мы не успеваем выполнить полный расчет до поступления следующего колбэка.
        Когда я писал роботов на QLua, то вынужден был делать main() достаточно насыщенным различными командами, и это приводило к высокой нагрузке на процессор и терминал начинал сильно тормозить (не забываем, что и терминал и все скрипты работают в одном потоке).
        Данная проблема частично решалась увеличением задержки в конце каждого цикла, но все равно со временем я «уперся в потолок» максимальной нагрузки, и вынужден был начать поиски способа перехода на C# (с параллельным изучением этого языка). Уже года 3 на QLua роботов не пишу. Теперь только на C#.
        • Igr
          19 февраля 2019, 10:04
          Prophetic, ну я цены из стакана беру, все расчёты сравнения в майн, когда в колбеках делал какие то расчёты вот тогда терминал подвисал не хило, когда перенёс всё в майн стало намного лучше, ну у меня 1 скрипт всего лишь работает, проц на 25% загружает, частота расчётов большая 
          • Prophetic
            19 февраля 2019, 14:15
            Igr, 
            1. В самих колбэках конечно же ничего делать нельзя. Только проверку на то, что это именно тот колбэк который Вы ждете, и в случае положительного результата — вызов нужной функции.
            2. В стакане нет информации о цене последней сделки по инструменту. только заявки спроса и предложения. Для ликвидных бумаг это не сильно принципиально, но во многих случаях это только заявки. Сделки — это совсем другая история. Но тут каждый сам решает, что ему нужно.
            3. На нескольких скриптах (до 10), при правильной организации структуры, потери терпимы. Я больше десятка роботов держал с визуальными интерфейсами каждый. Но нужно помнить, что критическая ошибка в одном роботе может привести к крэшу всего терминала, со всеми вытекающими последствиями. При любых раскладах, логика работы робота за пределами процесса терминала — это только благо. Но пока лично не столкнетесь с этими проблемами, понять меня будет непросто.
            • Igr
              19 февраля 2019, 14:48

              Prophetic, 

              1. но вот вызов нужной функции, ведь эта функция будет ыполнятся именно в колбэке, т.е. если функция выполняется долго то всё зависнит, так ведь? 

              3. да всё логично, вполне понятно)  

               

              а вообще скрипт написанный в клуа какое то преимущество имеет перед скриптом на си, т.е. луа же вписан в квик, не быстрее ли он действует чем сторонняя прога на си ?  

              • Prophetic
                19 февраля 2019, 17:11
                Igr, 
                1. Досконально не проверял, но общая суть верна. Можете попробовать немного обмануть систему, запрещая выполнять какую-либо обработку данных в колбэке, пока не завершилась работа функции от предыдущего вызова.

                Фактически — никаких преимуществ, с точки зрения производительности, нет. Только проблемы. Для HFT квик все равно не годится, а для всех прочих задач грамотный коннектор обеспечивает достаточное быстродействие, чтобы вообще не задумываться о скорости обмена информацией между роботом и терминалом.
                Скажем так: QLua хорош на начальном этапе освоения роботостроения (в области биржевой торговли). Написав пару десятков роботов на этом языке, и освоив начальный уровень программирования на C#, можно достаточно быстро и без особых проблем перейти на С#.
                Я потратил несколько месяцев на самостоятельное изучение C#, а примерно через полгода, после того как нашел коннектор, написал первого полноценного робота на этой платформе.
                • Igr
                  19 февраля 2019, 17:13

                  Prophetic, разве HFT не торгуют через квик? 

                  а через что? 

                  • Prophetic
                    19 февраля 2019, 17:46
                    Igr, для HFT на первом месте стоит скорость получения данных и вывод собственных заявок на площадку. Ни одна связка квик-брокер-биржа не может обеспечить достаточную скорость (в нынешних реалиях).
                    Для HFT используют прямое подключение к бирже (например Plaza), вплоть до установки своих серверов в стойку, которая расположена максимально близко к серверам биржи. На сегодняшний день HFT — это удел достаточно серьезных игроков, которые вкладывают очень большие деньги в инфраструктуру. Для простых одиночек эта область стала практически недоступна (раньше, конечно, было не так).
                    • Igr
                      19 февраля 2019, 17:50
                      Prophetic, а прямое подключение идёт без квика вообще? там же какой то должен быть терминал? 
                      • swerg
                        19 февраля 2019, 21:29
                        Igr, Сами позиции вы можете контролировать через терминал, но робот работает совершенно отдельно. И не через QUIK. Во всяком случае не через клиентские терминал QUIK, с которым вы обычно работаете. Прямой коннект по протоколу биржи или через стандартизованный для этого дела протокол FIX
                      • Prophetic
                        20 февраля 2019, 09:21
                        Igr, Да, без квика вообще. И терминала там никакого нет. Есть программный доступ к определенному набору данных (примерно таких же как в квике). Вы эти данные можете обрабатывать как угодно, а на биржу только отправляете транзакции на выставление или удаление заявок.
                        Это сильно упрощенное объяснение.
                        Вот, можете почитать, если интересно: https://www.moex.com/s444

                        • Igr
                          20 февраля 2019, 10:06

                          Prophetic, понятно, спасибо 

                          но как это вообще выглядит, вот у вас робот написан на си под квик, как вы его подключаете к PLAZAII ?  а если на клуа писан его вообще не получится использовать? 

                          • Prophetic
                            20 февраля 2019, 17:09
                            Igr, Робот, который написан на C# по квик, подключается к терминалу через специальную программу-коннектор (в моем случае QUIKSharp).
                            Что касается плазы, то до практической реализации я не доходил (не возникло необходимости), но предполагаю, что подходи будет похожим, т.е. надо будет написать программу-коннектор, которая будет подключаться к серверу и транслировать данные вашим роботам, а роботы, соответственно, будут получать данные от этого коннектора, обрабатывать их и через него же отправлять транзакции на сервер.
                            Робот, написанный на QLua никак нельзя подключить к плазе (во всяком случае, мне неизвестны такие способы).
                            • Igr
                              20 февраля 2019, 17:11
                              Prophetic, спасибо 
  • Иван Иванов
    18 февраля 2019, 17:45
    Поток бесконечно выполняется не задерживаясь ни на милисекунду.
    надо давать ему поспать когда нет работы )
  • swerg
    19 февраля 2019, 21:26
    Про устройство QLua и как оно функциклирует в рамках терминала QUIK можно почитать тут
    quik2dde.ru/viewtopic.php?id=16
  • swerg
    19 февраля 2019, 21:31
    Вы пишете, что процессор загружен на 100%. В смысле весь процессор (а не одно ядро) загружен на 100%? У вас может одноядерный процессор? это экзотика по нашим временам

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн