Блог им. VinniPuh_3af

Вопрос алготрейдерам: у вас Квик не зависает при срабатывании OnStop() ?

Столкнулся с такой проблемой буквально на последних паре версий 8.8.1 и 8.8.4

В чем проблема: при остановке скрипта квик стал «уходить в себя» (зависать).
Останавливается скрипт банально через OnStop()

Логика там проще некуда:

IsRun = true

OnInit()
     CreateDataSource()
end

main()
     while IsRun do
         getCandlesByIndex()
         --доп. запрос данных с индикатора
         --и после вычисления
     end
end

OnStop()
     IsRun = false
end

Все. Структура как по учебнику. Все расчеты внутри main. Никаких допов не подключается, все расчеты сугубо арифметические.
Считают каждую минуту при появлении новых данных по свечам.
После остановки скрипта считать нечего. С рояли он зависает?

Причем весь парадокс в том, что подобное происходит только после продолжительной работы скрипты (где-то от часа и более).
Запущенный и выключенный через 10-15 минут не зависает.

Впечатление будто скрипт в момент остановки не понимает куда сбросить накопившиеся за время работы данные, хотя:

Lua uses automatic memory management that uses garbage collection based on certain algorithms that is in-built in Lua. As a result of automatic memory management, as a developer −

  • No need to worry about allocating memory for objects.
  • No need to free them when no longer needed except for setting it to nil.

Вопрос не в силе железа или объеме памяти. 

Подскажите, кто с таким сталкивался?


UPD:
Переписал OnStop() добавив return:

function OnStop()
     IsRun = false
     return 5000
end

Тесты в интервале до 127 минут с прерыванием в разное время проблем не выявило.
Вся структура кода не менялась.
С таким бредом я еще не сталкивался.

Большое спасибо всем неравнодушным.

  • обсудить на форуме:
  • Quik Lua
★1
40 комментариев
Нет, не зависает. Последние версии ещё не ставил, пока 8.5…
В ОнСтоп после Фалсе ещё Слип делаю на пару секунд.
А вообще, по хорошему перед Фалсе надо отписаться от данных.
avatar
3Qu, слип не помогает, тоже стоит.
Отписка это CreateDataSource():Close , речь про нее?

Я оттестил два вида источника данных, с графика и через ds. Оба глохнут, хоть и визуально ds шустрее отлагивает.
avatar
Винни Пух, 
Отписка это CreateDataSource():Close , речь про нее?
Да, про нее.
А Слип, чтобы подождать пока Мейн завершится.
Ну, и спутал, отписка после выхода из цикла
OnStop()
     IsRun = false
    Sleep(2000)
    CreateDataSource():Close
    sleep(1000) --это возможно и не надо.
end
Как-то так. Компа нет, подсмотреть негде.
avatar
3Qu, в мануале OnStop() описан как функция, которая дает 5 сек на завершение скрипта, если не задано иное (через return)
Т.е. по логики там и не нужно ничего вписывать, хотя в примерах чаще всего присутствует дополнительный слип.
avatar
Винни Пух, это скорее аварийное завершение, и сделано для этого.
В любом языке перед остановкой/завершением программы все ресурсы надо освобождать руками.
avatar
3Qu, После такого кода квик будет висеть 3 секунды. Останавливать основной поток — слабоумие и отвага.
avatar
Александр, либо не понял, либо вы что-то не понимаете. Поток main() на Квик вообще никак не влияет, т.к. main() выполняется в своем отдельном потоке, а не в потоке терминала. main() может вообще заниматься чем угодно, и на терминал это никак не повлияет. Что main() и делает, для чего и предназначен.)
avatar
Мне думалось, что Onstop() должен обязательно располагаться до вызова  main()

А если зависает, то намертво? Или через 5-10 секунд останавливается?
avatar
pessimist, отлагивает, когда минута, когда больше.
OnStop без разницы где. Это просто внутрянка и она спит до нажатия кнопки «Остановить». Как кнопка нажимается, вызывается OnStop()
avatar
Винни Пух, 
отлагивает, когда минута, когда больше

Я бы подумал, что процесс main завершается, а далее — вызывается Onstop еще раз и непонятно, что должно произойти. А скрипт завершает уже сам интерпретатор.

Если забить комментом функцию Onstop и скрипт намертво не повиснет, а будет реагировать на кнопку «Остановить», значит трабла в том, что Onstop описана после main()
avatar
pessimist, 
из того, чему я учился, следовало так:
При нажатии «Остановить» вызывается OnStop(), в ней задается переменная false, далее main начинает новый обход, видит false и завершается.

Функция вызывается терминалом QUIK при остановке скрипта из диалога управления и при закрытии терминала QUIK.

Функция возвращает количество миллисекунд, которое дается скрипту на завершение работы. Если функция не возвращает число, то таймаут завершения работы скрипта остается равным 5 секундам

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


т.е. даже если я не останавливаю вечный цикл в main, его принудиловкой закрывают.
Где-то в этом моменте зарыта собака.

upd: непрерывная работа скрипта 30 мин — завершение в течении 2 секунд, как и задал.

Положение ONStop() внутри скрипта до или после main значения не имеет, оттестил.
avatar
pessimist, ОнСтоп без разницы куда ставить. Главное, чтобы он переменные видел. А он их видит только если они объявлены вне других функций и до ОнСтоп.
avatar
3Qu, Все так.
avatar
3Qu, 
ОнСтоп без разницы куда ставить. Главное, чтобы он переменные видел. А он их видит только если они объявлены вне других функций и до ОнСтоп.

Ну, я предположил, что что-то не то с IsRun из-за того, что закончился main, смутно представляю себе поведение интерпретатора после завершения потока main...

Других идей — нет. Если скрипт зависает — значит зависает while… А почему зависает цикл, особенно, если раньше такого не было — куча вариантов. Вплоть до кривой реализации штатных функций QLUA, типа CreateDataSource()
avatar
pessimist, парадокс в том, что у меня местами натыканы слипы на случай кривизны рук, и после

while IsRun do
sleep(10)

сразу идет мелкий слип.

Даже если while и виснет, то делает это через паузу 0,01 сек, чего в целом достаточно чтобы программа сообразила о том, что её завершают.


Поэтому я и заступорился в своих рассуждениях почему так. 
avatar
Винни Пух, 

Ну дык, я правильно понимаю, что CreateDataSource():Close все полечило?
avatar
pessimist, нет, я не использовал это.
Вообще ничего не использовал, кроме написания как в мануале return 5000 для ф-ции OnStop.
Все остальное неизменно.
15 мин работы не виснет, 50 мин не виснет. Теперь буду ждать 2 часа и потом стопить.
avatar
Винни Пух, 

Теперь буду ждать 2 часа и потом стопить.

Жаль, а я, уж, подумал, что все ОК 
avatar
Винни Пух, я так понимаю, код в топике неполный.
Мы что видим, то и поем.
avatar
3Qu, после main еще «рукописные» функции, но все связанные с расчетом цен и вызываемые только в main.


так что основной код полный. 
avatar
Винни Пух, 

Я бы все-таки main поставил в самый низ. Ничего не могу утверждать, но как-то стрёмно видеть описание пользовательских функций ниже основного потока... 
avatar
Винни Пух, особенно этот
OnInit()
     CreateDataSource()
end
)) Подписка ни на что.)
Не то что вам нужно, но тоже самое в моем исполнении:
function main()
        ds_s, Err1 =CreateDataSource (EX_CODE, FUT_S, INTERVAL_M1) --создаем источник данных *)
        if Err1 == "" or Err1 == nil then
                message("Подписка ОК 1")
                while not (ds_s:Size() >0) do
                        sleep(10)
                end
        else            
                message("Ошибка 1" .. Err1)
        end
        Err1 = ds_s:SetUpdateCallback (cbCandleS) --определяем функцию события терминала, получащую данные свечи. *)
--<br /><br />Взято из одного из моих топиков на СЛ.<br /><br />Кстати, ds_s определена вне main()
avatar
3Qu, 

не понял...
Таблица уходит в переменную вот так
ds = CreateDataSource( p_CLASSCODE, p_SECCODE, INTERVAL_M1)

её можно и не инициализировать здесь, т.к. обращение к ней идет в main до запуска бесконечного цикла. Т.е. её роль в ошибке нулевая, т.к. я переписал сегодня код без CreateDataSource()

avatar
Винни Пух, в моем коде это необходимо, т.к. ds_s используется вне main(). В частности определяется функция обработки события
Err1 = ds_s:SetUpdateCallback (cbCandleS) --определяем функцию события терминала, получащую данные свечи. *)
которая также использует ds_s.
Я и написал, что это не совсем то, что у вас, а как пример другого подхода. В данном случае, событийного.
avatar
Винни Пух, да, и ещё.
Имхо, надо не CreateDataSource():Close, а ds_s:Close()
avatar
Прежде чем задавать вопросы посторонним людям, которые не видят твой код, надо самому задать вопросы своему коду.
Принципы экстремального программирования.
Разработка с нуля по этапам с отладкой каждого этапа.
Нулевой этап: только OnStop() и main() с минимальным кодом.
Если на этапе 0 сбоя нет, можно наращивать код на следующих этапах.
avatar
Rostislav Kudryashov,
Прежде чем задавать вопросы посторонним людям.........

Однако, посторонние люди разобрались все-таки быстрее :)
avatar
pessimist, 16:56 === посторонние люди разобрались все-таки быстрее
===
На какой минуте? Покажи «пальцем».
avatar
Rostislav Kudryashov, 
На какой минуте? Покажи «пальцем».

smart-lab.ru/blog/645552.php#comment11611697
avatar
pessimist, 17:02 это называется, «уклончивый ответ». Ценю твою воспитанность — твой ответ равноценен посылу на 3 буквы, но как деликатно!
avatar
Rostislav Kudryashov, я заблуждался — прочел коммент ТС

3Qu, Все так.

Оказывается, это не равнозначно «Ура, заработало!!!»


avatar

Не зависает.

Потому что торговые приказы и их коллбэки обрабатываются через trans2quik.dll

avatar
Ваще-та, зависание на 5 сек при закрытии — это минимальный режим по умолчанию. Если хочется сократить это время, то в OnStop() нужно добавить время выгрузки return(n), где n — миллисекунды.
А еще внутри робота (где-нибудь в конце) прописать collectgarbage ().
avatar
Eugene Bright, про мусор в мануалах пишут что луа сам рулит ситуацией, да и там нет мусора, каждый раз создается новый массив, т.е. предыдущий уничтожается.
return прописал, потестил, с ним вроде все ок.
avatar
Винни Пух, есть ли мусор, нет ли мусора — это нам неизвестно, но почему бы не помочь железяке почистить мозги?..
avatar
Eugene Bright, collectgarbage () нужен только в случае использования оч больших массивов, кот вам больше не нужны. В остальных случаях штатного сборщика достаточно.
Однако, для больших данных достаточно и var = nil. И уж, если приспичит, тогда уж после этого collectgarbage ().
avatar
3Qu, дык, изначально Вы ж не обозначили, большие или нет таблицы у Вас, потому и совет был «на всякий (!) случай».
avatar
Eugene Bright, 18:24 множество мелких манипуляций бывают накладнее одной большой.
avatar
Rostislav Kudryashov, бывают, бывают… )))
avatar
Зависание намекает на то, что выход из длинного цикла приводит к какому-то конфликту. Имеет смысл понаблюдать за изменением объема занимаемой памяти во время работы скрипта. Это самый примитивный способ диагностики косяков в коде.

Но для начала я бы закомментил весь код внутри while и понаблюдал за жизнью голого скрипта и поведением терминала… если все ОК, то раскомментил бы половину кода… и снова прогон… и т.д.))
avatar

теги блога Винни Пух

....все тэги



UPDONW
Новый дизайн