База скрипта в QLua (lua)

Автор записи: Дмитрий (Admin)

-- Это основная функция скрипта, которая работает в отдельном от QUIK потоке,
-- это означает, что если QUIK будет перегружен работой,
-- например, при большом объеме поступающих сделок,
-- то QLua - скрипт продолжит выполнять свою работу в штатном режиме,
-- при условии, что у QUIK найдется процессорное время для того, чтобы "выдать" скрипту
-- необходимую информацию для работы (если она ему потребуется)
function main()
   -- здесь будет Ваш код
end;
-- Если запустить такой скрипт, то эта функция выполнится 1 раз и скрипт остановится.

-- Если Вам нужно постоянно выполнять какой-то код,
-- то для этого нужно внутри этой функции расположить т.н. "бесконечный цикл",
-- но для того, чтобы возможность остановить скрипт все-таки была,
-- делается подобным образом:
 
IsRun = true;
 
function main()
   while IsRun do
 
   -- здесь будет Ваш код
 
   sleep(1);
   -- ОБЯЗАТЕЛЬНО !!!(это пауза в 1 миллисекунду), ИНАЧЕ СКРИПТ БУДЕТ СИЛЬНО НАГРУЖАТЬ ПРОЦЕССОР
   -- И ПРИ ЗАВЕРШЕНИИ ТАКОГО СКРИПТА QUIK МОЖЕТ АВАРИЙНО ЗАВЕРШИТЬ СВОЮ РАБОТУ
   end;
end;
 
function OnStop()
   IsRun = false;
end;
 
-- Функция OnStop вызывается автоматически, когда пользователь нажимает кнопку "Остановить",
-- или закрывает терминал.
-- Внутри этой функции можно расположить какой-то свой код,
-- который нужно выполнить по завершению работы скрипта.
-- В данном случае при завершении скрипта переменной IsRun присваивается ЛОЖЬ,
-- после чего цикл while внутри функции main перестает выполнятся и скрипт останавливается.
 
-- ВАЖНО!!! Не помещайте в эту функцию код, которому нужно много времени для выполнения,
-- потому что, время выполнения этой функции ограничено примерно 5-ю секундами.
-- Так же, как OnStop, существует функция инициализации Init,
-- которая, в отличие от OnStop, выполняется до запуска скрипта,
-- перед началом работы функции main
 
IsRun = true;
 
function OnInit()
   -- Здесь будет Ваш код для начальной инициализации
end;
 
function main()
   while IsRun do
 
   -- Здесь будет Ваш код,
   -- который будет выполнятся,
   -- пока скрипт не остановлен
 
   sleep(1);
   end;
end;
 
function OnStop()
   -- Здесь будет Ваш код,
   -- который нужно выполнить
   -- перед остановкой скрипта
   IsRun = false;
end;
Сказочка про работу скрипта 🙂
Функция main выполняется в отдельном потоке, в этом весь смысл, чтобы его понять лучше, запустите вот такой скрипт:

1
2
3
while true do
   sleep(10000)
end

Попробуйте что-то сделать в терминале после запуска такого скрипта. Ваш терминал будет «висеть» 10 секунд, потому что цикл while будет выполняться в основном потоке терминала, в том же где происходит все взаимодействие с пользователем, т.е. с Вами.
Потом запустите вот такой скрипт:

1
2
3
4
5
function main()
   while true do
      sleep(10000)
   end
end

Здесь тот же самый цикл, только уже внутри main, после запуска такого скрипта терминал будет работать как обычно, как будто никакого скрипта и не выполняется, потому что для функции main терминал создаст отдельный поток, параллельный основному. Чтобы понять что такое потоки, можете сравнить их с рабочими на фабрике, один рабочий — один поток. Представьте, что у Вас есть один рабочий, который занимается отрисовкой всего в терминале, он все отрисовывает, все работает, все хорошо. И тут Вы ему говорите: «Выполни мой скрипт», он говорит: «Хорошо», бросает отрисовку, начинает выполнять Ваш скрипт и видит там команду sleep(10000), для него это означает «ничего не делай 10 секунд», он говорит: «хорошо», и просто сидит на стуле 10 секунд 🙂 Естественно никто в это время ничего в терминале не перерисовывает и не реагирует на действия пользователя. Посидел работник 10 секунд и дальше продолжил заниматься отрисовкой, терминал «ожил». А вот если Вы ему «скажите» выполнить второй скрипт с main, то он, увидев main, подзывает другого работника, который ничего не делал и перекладывает эту задачу на него, а сам продолжает заниматься отрисовкой, т.к. наш первый работник у них главный, он может другим задачи распределять 🙂 Второй работник начинает выполнять все, что находится в функции main и никак не отвлекает «бригадира» от его работы.

Сразу могу провести аналогию с функциями обратного вызова. Если, например, мы запустили такой скрипт:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
run = true
 
function main()
   while run do
      sleep(10)
   end
   message('Пока')
end
 
function OnTrade()
   message('Появилась новая сделка')
end
 
function OnStop()
   run = false
end

«Бригадир» смотрит что в нем сверху вниз, видит run = true, записывает себе в журнал, что в таком-то скрипте есть переменная run и она равна true, смотрит дальше, есть функция main, значит нужно будет привлечь другого работника, смотрит дальше, и видит функцию обратного вызова OnTrade, а в должностной инструкции бригадира написано, что это его обязанность обрабатывать функции обратного вызова, он у себя помечает в журнале, что когда придет информация о сделке пользователя, он должен выполнить эту функцию в этом скрипте, смотрит дальше, и видит что есть, так же, функция обратного вызова OnStop, опять помечает у себя в журнале, что если пользователь нажмет кнопку «Остановить» выделив перед этим данный скрипт в окне «Доступные скрипты», то он должен выполнить эту функцию . После этого он, как обычно, подзывает работника, говорит ему выполнять main и продолжает заниматься своей работой по обслуживанию терминала. Работник начинает выполнять то, что в main, смотрит, а в ней цикл «ПОКА(while) переменная run равна true ДЕЛАТЬ(do) «, проверяет переменную run, а она действительно равна true, и начинает делать то, что внутри цикла написано, видит там паузу 10 миллисекунд, ничего не делает 10 мс, идет дальше, видит там end, значит конец цикла, но так как это цикл, то он возвращается обратно к while и снова проверяет значение переменной run, оно по прежнему true и он опять выполняет паузу, и будет продолжать так делать, пока(while) переменная run равна true.
А в это время в терминал приходит информация, что по выставленной пользователем ранее заявке совершилась сделка, бригадир, получив эту информацию, смотрит свой журнал и видит, что при таком событии он должен выполнить функцию OnTrade в нашем скрипте, что он и делает, видит, что он должен вывести сообщение с текстом «Появилась новая сделка», делает это и продолжает заниматься своей работой. Сделок может быть много и каждый раз он будет выводить сообщение.
Потом вдруг нам надоело получать эти сообщения о сделках и мы нажали кнопку «Остановить» для этого скрипта. Бригадир опять читает свой журнал и видит, что должен выполнить функцию OnStop прежде, чем завершить наш скрипт. Переходит к ее выполнению, смотрит, а там написано, что он должен переменной run присвоить значение false, что он и делает, а так же ставит себе таймер на 5 секунд, после срабатывания которого он должен работнику, который выполняет main дать приказ завершить все работы и исчезнуть куда-нибудь, если он сам не придет в течении этих 5 секунд и не скажет, что он все выполнил 🙂
А в это время работник, в очередной раз проверяя значение переменной run, обнаруживает, что она уже не равна больше true, а равна false, а значит не нужно больше выполнять цикл, он переходит к тому, что ниже цикла, видит, что должен вывести сообщение с текстом «Пока», делает это, смотрит дальше, а дальше конец функции main, а значит и конец его работы. Радостный он бежит к бригадиру, сообщает, что все сделал, бригадир отпускает его с работы домой, а у себя из журнала вычеркивает переменную run и функции OnTrade и OnStop, после чего продолжает заниматься своей работой, как будто этого скрипта никогда и не было 🙂

Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!