Корректная рекурсия

Страницы: 1
RSS
Корректная рекурсия, Как корректно оформить рекурсию в Lua (функция ссылается сама на себя)
 
Рекурсия - когда функция ссылается сама на себя - вещь не самая удачная в программировании, однако иногда она все же нужна для работы роботов в Луа.
В частности у меня написана функция инициации робота, которая вызывает сама себя, в случае, если нет соединения с сервером. Иными словами, в определенной точки функции, если не считаны параметры времени сервера (т.е. очевидно нет связи с ним), оператором sleep инициируется пауза в работе скрипта, а затем, функция вызывает сама себя и запускается с начала.
Выглядит это в общих чертах  так:

function OnInit()
theDate = 0 -- инициируем переменную, которая будет содержать текущую дату
InitBeforSession = false -- инициация перед началом сессии
InitEveryDay () -- ежедневная инициализация
end

function InitEveryDay ()
message ('Proliv InitEveryDay start')
sleep (100)

-- Индикаторы состояния торговли
isTempStoped = false; -- временная остановка работы скрипта
isTrades = false; --есть ли торги по фьючерсам?
isTradesPrevious = false
isConnectedPrevious = false
isConnected = false

-- Флаги работы скрипта
is_run = false -- флаг работы цикла Main


-- Проверка на наличие соединения
if dDT.year == nil then -- если значения полей пустые, значит нет соединения с сервером !!! по-видимому здесь происходит какое-то зацикливание из-за которого quik намертво виснет при запуске  в период когда нет соединения с сервером
message ("Error: no connection")
sleep (5000) -- стоим на месте
InitEveryDay ()
end -- если значения полей пустые

end -- конец функции

function main()
-- Задерживаем старт main до исполнения кода onInit (после его завершения флаг stopMain будет переведен в false - см. выше)
message ("main - stopMain ")
while stopMain do -- старт  стопора while
sleep (500)
message ("main stopMain is  "..tostring(stopMain))
end -- конец стопора while
end

---------------------------

Проблема в том, что при неблагоприятных условиях, в частности если скрипт стартуется при отсутствии соединения с сервером, скрипт виснет и вешает Квик, приходится аварийно перезагружать программу.
Эта схема рекурсии с паузой и оператором sleep, как я увидел, неработоспособна и во всех других случаях, когда она регулярно (многократно) срабатавает.
В чем проблема? И как реализовать данную задачу корректно: скрипт многократно пытается инициироваться, пока не наступят благоприятные условия.
 
Здравствуйте,
Из документации:
Цитата
Функции обратного вызова обрабатываются в основном потоке терминала QUIK. Поэтому пользователю необходимо оптимизировать время исполнения таких функций.

В связи с чем любой бесконечный или долгий цикл в любом колбеке может подвесить терминал.
Надо перенести проверку в функцию main
 
Цитата
Sergey Gorokhov написал:
Здравствуйте,
Из документации:
Цитата
Функции обратного вызова обрабатываются в основном потоке терминала QUIK. Поэтому пользователю необходимо оптимизировать время исполнения таких функций.

В связи с чем любой бесконечный или долгий цикл в любом колбеке может подвесить терминал.
Надо перенести проверку в функцию main
Правильно ли я понимаю, что в таком случае рекурсия в принципе недопустима ни в одной из функций скрипта Lua? Корректная последовательность приблизительно такова: функция должна быть исполнена до конца, вернуть условное негативное значение, после чего, с некоторой паузой должен произойти ее повторный вызов из main, в моем случае видимо из блока while stopMain do...

Коллеги, можете ли поделиться примерами ежедневной реинициализации скрипта?
 
Цитата
Иван Ру написал:
Правильно ли я понимаю, что в таком случае рекурсия в принципе недопустима ни в одной из функций скрипта Lua?

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

Цитата
Иван Ру написал:
Коллеги, можете ли поделиться примерами ежедневной реинициализации скрипта?

Все зависит от того что для Вас "реинициализация", и вообще почему выбран именно OnInit, а не скажем OnConnected.
И почему "if dDT.year == nil", а не функция isConnected()
И что мешает все тоже самое сделать в цикле "while stopMain do", а в колбеках оставить только переменные?
 
"Во вторых, как уже было сказано, нежелательно их использовать только в колбеках, а значит..."
Насколько я понимаю, функцию InitEveryDay, где имеется рекурсия не относится к коллбэкам.

ВОПРОС: "Все зависит от того что для Вас "реинициализация""
ОТВЕТ: ежедневное обновление ключевых параметров скрипта, это не OnInit, которая является коллбэком, а функция InitEveryDay. Она вызывается из OnInit, а также из еще одной функции (не колл-бэка) скрипта, которая фиксирует смену даты.

ВОПРОС: "И что мешает все тоже самое сделать в цикле "while stopMain do", а в колбеках оставить только переменные?"
ОТВЕТ: Так все-таки не получится. Этот блок проходится (функционирует) единожды -- когда скрипт инициирован (запущен), но не завершена его инициация. InitEveryDay вызывается ежедневно, в том числе, когда этот блок пройден. Я рассчитываю что мой скрипт должен работать много дней без перезапуска, собственно для этого и нужна функция InitEveryDay  
 
Цитата
Иван Ру написал:
"Во вторых, как уже было сказано, нежелательно их использовать только в колбеках, а значит..."
Насколько я понимаю, функцию InitEveryDay, где имеется рекурсия не относится к коллбэкам.
А вызываете Вы её как раз в коллбэке - в OnInit
Цитата
Иван Ру написал:
function OnInit()
    ...
    InitEveryDay () -- ежедневная инициализация
end
 
напоминает шутку про индийского программиста, который чтобы узнать завтрашнюю дату, делал в программе sleep на сутки.
зачем вообще рекурсия?

сделайте в main
while dDT.year == nil do
 InitEveryDay ()
 sleep(xxx)
 if stopped then
   break
 end
end

while not stopped do
-- основной цикл
end

а в InitEveryDay уберите и рекурсию и sleep, там это не нужно.

не нужно из колбэков вызывать тяжёлую и долгую логику, будет подвисать весь квик
 
Цитата
Павел Bosco написал:
напоминает шутку про индийского программиста, который чтобы узнать завтрашнюю дату, делал в программе sleep на сутки.зачем вообще рекурсия?сделайте в main while dDT.year == nil do   InitEveryDay ()   sleep(xxx)  if stopped then    break  endendwhile not stopped do-- основной циклendа в InitEveryDay уберите и рекурсию и sleep, там это не нужно.не нужно из колбэков вызывать тяжёлую и долгую логику, будет подвисать весь квик
Коллеги, просьба вести диалог в уважительном тоне, или хотя бы читать внимательнее!
При предложенном Вами исполнении, Павел Bosco, функция InitEveryDay  будет вызваться в лучшем случае единожды за все время работы скрипта -- тогда когда будет впервые установлено соединение с сервером. Выше несколько раз было сказано, что необходима ежедневная реинициализация параметров, т.е. многократное обращение к функции InitEveryDay , собственно, это даже из ее названия  понять можно!
Принципиальное решение  мне понятно -- функция вызывается при соблюдении двух обязательных и достаточных условий - соединения с сервером и смены даты. При этом ее вызов должен происходить один раз (нужен флаг сбрасываемый при смене даты).
Что касается замечания vgi, еще раз отмечу, принципиально то, что рекурсия в данном случае находится не в коллбэке. Не имеет значение откуда вызывается функция с рекурсией, она у меня может вызываться разными способами, в т.ч. и не из коллбэка, но результат плачевный в любом случае. Поэтому я и задал важный уточняющий вопрос  для Sergey Gorokhov -- я вижу что рекурсия приводит к подвисанию независимо от того в коллбэке она или нет.  
 
Цитата
Иван Ру написал:
то, что рекурсия в данном случае находится не в коллбэке

Вы категорически не правы, Вам уже несколько человек об этом сказали.
Вызывая функцию в колбеке, Вы вызываете ее в колбеке, это же очевидно разве нет?
Цитата
Иван Ру написал:
function OnInit()
theDate = 0 -- инициируем переменную, которая будет содержать текущую дату
InitBeforSession = false -- инициация перед началом сессии
InitEveryDay () -- ежедневная инициализация
end

Уберите InitEveryDay из OnInit и не будет зависать
 
Цитата
Иван Ру написал:
При предложенном Вами исполнении, Павел Bosco, функция InitEveryDay  будет вызваться в лучшем случае единожды за все время работы скрипта -- тогда когда будет впервые установлено соединение с сервером. Выше несколько раз было сказано, что необходима ежедневная реинициализация параметров, т.е. многократное обращение к функции InitEveryDay
В Вашем изначальном варианте InitEveryDay точно так же вызывается единожды при старте скрипта.

Если требуется "ежедневная переинициализация" в InitEveryDay
● проверяйте isConnected()
● проверяйте дату торгов getInfoParam ("TRADEDATE ") и если она измененилась по сравнению с предыдущей запомненной делайте, что Вам требуется
● если работаете из одного и того же часового пояса, проверяйте локальное время, почему нет!
откажитесь от рекурсии, она вводит Вас в заблуждение. Сейчас у Вас в коде рекурсия ради рекурсии, а не достижения цели. Обычный while  вполне сгодится.
 
на самом деле в теме написана не рекурсия, а бесконечный цикл вызова функции с ожиданием события подключения.
Это новон слово в программировании.  Я бы так не догадался сделать цикл.
 
так как такое решение просто напрочь забивает стек и грузит процессор по самые...
 
Цитата
vgi написал:
isConnected
Спасибо. В принципе я так уже и сделал.
Функция вызывается из нескольких мест, в примере видно только одно, в частности она вызывается при смене даты. Рекурсию надо убрать конечно и в принципе нигде ее не допускать, в данном исполнении она действительно может превратиться в бесконечный цикл с запуском бесконечного количества экземпляров функции.  
 
Цитата
Иван Ру написал:
При предложенном Вами исполнении, Павел Bosco, функция InitEveryDay  будет вызваться в лучшем случае единожды за все время работы скрипта  

да мой пример даже и не компилируется. потому что это пример. я предложил вам вариант переписывания функции. выбросите оттуда sleep, выбросите вызов самой функции из себя, и всё у вас получится.
откуда и как её вызывать - дело ваше.
то что к моему предложению надо было добавить вызов из нескольких колбеков, не делает его неправильным.

раз уж просите помощи на форуме, то не надо отвечать всем, что вы правы, и вас никто не понял.
по-поводу шутки, у меня сложилось впечатление, что вы не понимаете, что такое рекурсия. и даже слабо понимаете, что такое цикл.

ещё, позволю себе совет, почитайте что такое синхронные и асинхронные вызовы.
вы пытаетесь через InitEveryDay  устроить синхронную функцию, у которой на выходе будет гарантированный результат.
отсюда и попытки работы с рекурсией.
я считаю что это вам не нужно. работайте с InitEveryDay  так, что иногда она не возвращает результат сразу, тогда надо просто подождать и снова её вызвать.
причём при ожидании продуктивнее будет делать какую-то полезную работу, а не просто sleep.
это меняет логику построения программы, но зависать ничего не будет.
синхронная логика - это узкое горлышко производительности.
Страницы: 1
Читают тему
Наверх