Винни Пух
Винни Пух личный блог
10 сентября 2020, 15:49

Вопрос алготрейдерам: у вас Квик не зависает при срабатывании 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 минут с прерыванием в разное время проблем не выявило.
Вся структура кода не менялась.
С таким бредом я еще не сталкивался.

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

40 Комментариев
  • 3Qu
    10 сентября 2020, 15:52
    Нет, не зависает. Последние версии ещё не ставил, пока 8.5…
    В ОнСтоп после Фалсе ещё Слип делаю на пару секунд.
    А вообще, по хорошему перед Фалсе надо отписаться от данных.
      • 3Qu
        10 сентября 2020, 16:18
        Винни Пух, 
        Отписка это CreateDataSource():Close , речь про нее?
        Да, про нее.
        А Слип, чтобы подождать пока Мейн завершится.
        Ну, и спутал, отписка после выхода из цикла
        OnStop()
             IsRun = false
            Sleep(2000)
            CreateDataSource():Close
            sleep(1000) --это возможно и не надо.
        end
        Как-то так. Компа нет, подсмотреть негде.
          • 3Qu
            10 сентября 2020, 17:10
            Винни Пух, это скорее аварийное завершение, и сделано для этого.
            В любом языке перед остановкой/завершением программы все ресурсы надо освобождать руками.
        • Александр
          10 сентября 2020, 18:50
          3Qu, После такого кода квик будет висеть 3 секунды. Останавливать основной поток — слабоумие и отвага.
          • 3Qu
            10 сентября 2020, 19:23
            Александр, либо не понял, либо вы что-то не понимаете. Поток main() на Квик вообще никак не влияет, т.к. main() выполняется в своем отдельном потоке, а не в потоке терминала. main() может вообще заниматься чем угодно, и на терминал это никак не повлияет. Что main() и делает, для чего и предназначен.)
  • pessimist
    10 сентября 2020, 16:03
    Мне думалось, что Onstop() должен обязательно располагаться до вызова  main()

    А если зависает, то намертво? Или через 5-10 секунд останавливается?
      • pessimist
        10 сентября 2020, 16:12
        Винни Пух, 
        отлагивает, когда минута, когда больше

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

        Если забить комментом функцию Onstop и скрипт намертво не повиснет, а будет реагировать на кнопку «Остановить», значит трабла в том, что Onstop описана после main()
        • 3Qu
          10 сентября 2020, 16:28
          pessimist, ОнСтоп без разницы куда ставить. Главное, чтобы он переменные видел. А он их видит только если они объявлены вне других функций и до ОнСтоп.
          • pessimist
            10 сентября 2020, 16:36
            3Qu, 
            ОнСтоп без разницы куда ставить. Главное, чтобы он переменные видел. А он их видит только если они объявлены вне других функций и до ОнСтоп.

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

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

                Ну дык, я правильно понимаю, что CreateDataSource():Close все полечило?
                  • pessimist
                    10 сентября 2020, 17:06
                    Винни Пух, 

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

                    Жаль, а я, уж, подумал, что все ОК 
                  • 3Qu
                    10 сентября 2020, 17:25
                    Винни Пух, я так понимаю, код в топике неполный.
                    Мы что видим, то и поем.
                      • pessimist
                        10 сентября 2020, 17:44
                        Винни Пух, 

                        Я бы все-таки main поставил в самый низ. Ничего не могу утверждать, но как-то стрёмно видеть описание пользовательских функций ниже основного потока... 
                      • 3Qu
                        10 сентября 2020, 17:50
                        Винни Пух, особенно этот
                        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()
                          • 3Qu
                            10 сентября 2020, 18:30
                            Винни Пух, в моем коде это необходимо, т.к. ds_s используется вне main(). В частности определяется функция обработки события
                            Err1 = ds_s:SetUpdateCallback (cbCandleS) --определяем функцию события терминала, получащую данные свечи. *)
                            которая также использует ds_s.
                            Я и написал, что это не совсем то, что у вас, а как пример другого подхода. В данном случае, событийного.
                      • 3Qu
                        10 сентября 2020, 18:07
                        Винни Пух, да, и ещё.
                        Имхо, надо не CreateDataSource():Close, а ds_s:Close()
  • Rostislav Kudryashov
    10 сентября 2020, 16:51
    Прежде чем задавать вопросы посторонним людям, которые не видят твой код, надо самому задать вопросы своему коду.
    Принципы экстремального программирования.
    Разработка с нуля по этапам с отладкой каждого этапа.
    Нулевой этап: только OnStop() и main() с минимальным кодом.
    Если на этапе 0 сбоя нет, можно наращивать код на следующих этапах.
    • pessimist
      10 сентября 2020, 16:56
      Rostislav Kudryashov,
      Прежде чем задавать вопросы посторонним людям.........

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

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

              3Qu, Все так.

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


  • FinSerfing
    10 сентября 2020, 17:30

    Не зависает.

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

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

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

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

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