Работа колбеков

Страницы: Пред. 1 2
RSS
Работа колбеков
 
Цитата
TGB написал:
Цитата
nikolz написал:
что не так?
   Наверное, из-за того, что в таблице:
Код
   local  sec_list       =  {
    {'SPBFUT',  'MMU6' },
    {'SPBFUT',  'SiU6' },
    {'SPBFUT',  'RIU6' },
    {'SPBFUT',  'USDRUBF' },
    {'SPBFUT',  'CNYRUBF' },
    {'TQBR',  'SBER' },
    {'TQBR',  'GAZP' }
}
  

  классы заданы для реального рынка.
возможно  Вы правы пока не проверял.
Но тогда это прикольно. По крайней мере для меня.
-------------------------------
Полагаю ,что правильный скрипт запускается при любой погоде.
-------------------------
А эти тупо молчат нет никаких сообщений об ошибках или о нелетной погоде .  
 
сделал свой тест на демо сервере
---------------
Так как скрипт рабочий и большой, то расскажу основные моменты, чтобы было понятно , что и как
--------------------
У меня все колбеки сделаны одинаков  таким образом:
Код
OnOr der=function(t) setQ(4,t);   end
Функция setQ  помещает таблицу параметров колбека t и ключ колбека в очередь.
В этой функции я добавил в параметры значение точного счетчика Windows   Этот счетчик считает с квантом 0.1 мкс
--------------------------------
В функции main  я в цикле обрабатываю элементы очереди
В данном тесте я из значения точного счетчика вычитаю  сохраненное его значения при записи в очередь
Результат пишу в лог файл
-------------------------------------------
Таким образом в лог файле я получаю время задержки от вызова любого колбека до начала обработки параметров этого колбека в main
Т е фактически это время задержки от момента записи в очередь до момента начала обработки элемента из очереди
Код
t(мкс)=12.7
t(мкс)=8.6
t(мкс)=8.6
t(мкс)=3.1
t(мкс)=6.2
...
t(мкс)=59.1
t(мкс)=60.7
t(мкс)=60.0
t(мкс)=59.7
...
t(мкс)=32.9
t(мкс)=25.0
t(мкс)=14.1
t(мкс)=12.7

Т е время задержки примерно 0.00006 сек
 
Тест был направлен не на измерение скорости работы скрипта, а на влияние работы скрипта на работу терминала, его интерфейса в первую очередь. Какой смысл показать, да ещё на демо, что main работает быстро.
У меня на демо тоже всё прекрасно. Переключаешься на реальный и во время  открытия рынка - терминал вкладки переключает по 30 секунд.  Была бы возможность инструментально измерить работу самого терминала - так и вопросов не было бы.

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

Аналогично и в периоды высокой ликвидности. В это время транзакции могут исполнятся минуты - это ожидаемо, но почему опять интерфейс также "умирает".

Я готов это списать на влияние работы скриптов. Но тогда хотелось бы понять, что именно и какие методы оказывают максимальное влияние. Иначе делаешь банальный скрипт, а эффект как будто модель на 100b считаешь.
 
Ок. Теперь исключим колбеки.

Берем скрипт и выкидываем их, будем просто читать раз в секунду цены и класть их в ту же очередь. Логи тоже уберем.
Код
local path = _G.getScriptPath()
package.path = path.."/?.lua;"

local bl1 = require('big_lib')
local bl2 = require('big_lib2')
local bl3 = require('big_lib3')
local bl4 = require('big_lib4')

local id = 'script1'
local logFile

local function log_tostring(...)
  local args = table.pack(...)
  if args.n == 1 then
    return tostring(args[1])
  end
  for i = 1, args.n do
    args[i] = tostring(args[i])
  end
  return table.concat(args, " ", 1, args.n)
end

local function log(...)
    if logFile==nil then return end
    logFile:write(log_tostring(...).."\n");
    logFile:flush();
end


local sec_list      = {
    {'SPBFUT', 'MMU6'},
    {'SPBFUT', 'SiU6'},
    {'SPBFUT', 'RIU6'},
    {'SPBFUT', 'USDRUBF'},
    {'SPBFUT', 'CNYRUBF'},
    {'TQBR', 'SBER'},
    {'TQBR', 'GAZP'}
}

local last_data = {}


local rev_lis = {}
for i = 1, #sec_list do
    rev_lis[sec_list[i][2]] = i
    last_data[sec_list[i][2]] = {}
end

local sleep         = _G.sleep
local isRun         = true

local t_id          = nil

-- local SeaGreen      = 12713921  --  RGB(193, 255, 193) нежно-зеленый
-- local RosyBrown     = 12698111  --  RGB(255, 193, 193) нежно-розовый
-- local GetCell       = _G.GetCell
-- local Highlight     = _G.Highlight
local SetCell           = _G.SetCell
local getParamEx        = _G.getParamEx
local getInfoParam      = _G.getInfoParam
local IsWindowClosed    = _G.IsWindowClosed

local Queue = {}
Queue.__index = Queue

function Queue.new()
   return setmetatable({first = 1, last = 0 }, Queue)
end
---  Записать в очередь --
function Queue:push(v)
   if v == nil then error('!!! Ошибка. Параметр v функции QueuePush nil') end
   local last = self.last + 1
   self[last] = v
   self.last = last
   return last - self.first + 1    -- количество элементов в очереди ---
end
---  Читать очередь  --
function Queue:pop()
   local  first =  self.first
   if  first > self.last then return nil   end
   local v, v1  =  self[first], self[first + 1]
   self.first = first + 1
   self[first] =  nil
   v1 = type (v1) == 'string' and #v1 or 0
   return  v, v1   -- v1 -длина следующего элемента (если строка) ---
end

-- Текущий размер очереди ---
function Queue:size()
   return self.last - self.first + 1
end

local queue = Queue.new()

local function process_queue()
    local n = 0
    local res = queue:pop()
    while res do
        n = n + 1
        local last_price = res[3]
        -- local lp = GetCell(t_id, 1, 0).value or last_price
        -- if lp < last_price then
        --     Highlight(t_id, 1, 0, SeaGreen, 0, 500)
        -- elseif lp > last_price then
        --     Highlight(t_id, 1, 0, RosyBrown, 0, 500)
        -- end
        SetCell(t_id, rev_lis[res[2]], 1, tostring(last_price), last_price)
        -- log(id, ' --- set pop value',  n, rev_lis[res[2]], last_price)
        res = queue:pop()
    end
    return n
end

local function GetPrice(class_code,  sec_code)
    local last_price = tonumber((getParamEx(class_code,  sec_code, 'LAST') or {}).param_value) or nil
    if last_data[sec_code][1] == last_price then return end
    local res = {}
    res.last_time  = tonumber((getParamEx(class_code,  sec_code, 'TIME') or {}).param_value) or 0
    if res.last_time == 0 then return end
    res.last_price = last_price
    if not res.last_price then return end
    local bid_depth  = tonumber((getParamEx(class_code,  sec_code, 'BIDDEPTHT') or {}).param_value) or 0
    res.best_bid   = bid_depth > 0 and tonumber((getParamEx(class_code,  sec_code, 'BID') or {}).param_value) or nil
    local ask_depth  = tonumber((getParamEx(class_code,  sec_code, 'OFFERDEPTHT') or {}).param_value) or 0
    res.best_ask   = ask_depth > 0 and tonumber((getParamEx(class_code,  sec_code, 'OFFER') or {}).param_value) or nil
    res.last_rec   = tonumber((tostring(getInfoParam('LASTRECORDTIME') or ''):gsub(':', ''))) or 0
    res.local_time = (tonumber((tostring(getInfoParam('LOCALTIME') or ''):gsub(':', ''))) or 0)
    res.time_diff  = math.abs(res.local_time - res.last_rec) + 10
    last_data[sec_code][1] = last_price
    queue:push{class_code,  sec_code, last_price}
end

local function event_callback(_, msg, par1, par2)
    if (msg == _G.QTABLE_CLOSE) then
        isRun = false
    end
    if msg == _G.QTABLE_CHAR then
        SetCell(t_id, par1, 2, tostring(par2), par2)
    end
end

local function CreateTable()

    t_id = _G.AllocTable()

    _G.AddColumn(t_id, 0, "sec", true, _G.QTABLE_STRING_TYPE, 15)
    _G.AddColumn(t_id, 1, "price", true, _G.QTABLE_DOUBLE_TYPE, 15)
    _G.AddColumn(t_id, 2, "edit", true, _G.QTABLE_DOUBLE_TYPE, 15)
    _G.CreateWindow(t_id)
    _G.SetWindowPos(t_id, 90, 120, 470, 300)
    for i = 1, #sec_list do
        _G.InsertRow(t_id, i)
        SetCell(t_id, i, 0, sec_list[i][2])
    end
    _G.SetTableNotificationCallback(t_id, event_callback)
end

function _G.main()

    CreateTable()

    -- logFile = io.open(path.."\\load_"..id.."txt", "w")

    local lt = 0
    local req_int = 1

    while isRun do

        local cwt = os.time()
        if cwt - lt > req_int then
            lt = cwt
            for i = 1, #sec_list do
                GetPrice(sec_list[i][1], sec_list[i][2])
            end
        end

        -- local s = os.clock()
        -- log(id, 'Enter main loop', os.date())
      IsWindowClosed(t_id)
        local n = process_queue()
        bl1.func1()
        bl2.func100()
        bl3.func200()
        bl4.func300()
        -- log(id, 'Exit main loop', os.clock()-s, 'in queue', n)
        -- log('---------------------------------------------------------------------------')
        sleep(60)
    end
end

function _G.OnStop()
    isRun = false
    if t_id and not IsWindowClosed(t_id) then
        _G.DestroyTable(t_id)
    end
end


Запускаем скрипты и нет влияния. Хоть 5 скриптов запускай. Но как только подключаем OnParam и пишем в очередь, то уже на трех заметно влияение на работу интерфейса теримнала.
 
Цитата
Nikolay написал:
Но как только подключаем OnParam и пишем в очередь, то уже на трех заметно влияение на работу интерфейса теримнала.
   Можно запустить скрипт из одной строки (хоть в песочнице, хоть в продуктиве):
Код
 for i = 1, 5000000000 do   end

  и любоваться на то, как весь интерфейс QUIK зависнет пока будет выполняться эта строка в потоке обрабатывающем:
1) все коллбеки (всех скриптов и всех пользовательских таблиц);
2) все графики;
3) весь графический интерфейс QUIK;
4) возможно что-то еще (например, трафик данных?).
  Разработчикам QUIK не стыдно наблюдать такое который год подряд?
 
Цитата
Nikolay написал:
Вот прямо сейчас смотрю на один из терминалов - банально время сервера в строке состояния изменяется скачками, замирая на длительный период. И так каждый раз при старте, что, в теории, нормально, т.к. приходят пакеты. Но не 15 минут же. На терминалах других брокеров это же занимает минуту, 5-ять иногда. И в это время отчетливо видно как с трудом совершаются любые операции с интерфейсом.

Аналогично и в периоды высокой ликвидности. В это время транзакции могут исполнятся минуты - это ожидаемо, но почему опять интерфейс также "умирает".

Я готов это списать на влияние работы скриптов. Но тогда хотелось бы понять, что именно и какие методы оказывают максимальное влияние. Иначе делаешь банальный скрипт, а эффект как будто модель на 100b считаешь.
О скачках времени сервера читайте здесь:
https://forum.quik.ru/forum1/topic9514/
 
Сами скачки волне ожидаемы в клиент-серверном взаимодействии. Ну не пришли ещё пакеты, бывает, если оставить в сторону реализацию обмена.
Но вот почему в эти периоды терминал становится "тупым" - уже не столь очевидно и вызывает вопросы. Как будто сделали блокирующий цикл, ожидающий пакеты, а интерфейс - да кому он нужен.
 
Цитата
Nikolay написал:
Но как только подключаем OnParam и пишем в очередь
А если какой-нибудь другой колбэк заюзать? Любой достаточно частый.
 
Просто мысли вслух. Таблицы обезличенных сделок и левел2 это тиковые данные, в то время как  OnParam приходит пакетами примерно раз в секунду. Я кто тому что и очереди и буфер  и тайм фреймы у них ме могут быть одинаковы. OnParam требует индивидуального подхода и подписок на параметры. Может собака в сомой обработке зарыта?
 
OnParam и OnQuote самые быстрые. Остальные не так часто.

Поэтому добавим пустой OnParam. Почти нет влияния. Хотя есть уже ощущение, что не так, как без скриптов. Опять же - только визуальный контроль.

Добавим внутрь колбека одну строку

tonumber((getParamEx(class_code,  sec_code, 'LAST') or {}).param_value)

И уже явно что-то есть.

Также, чисто субъективно, кажется, что если дать ностояться, т.е. поработать скриптам, то уже как-то сильнее влияние.

Еще из странного - зависит от сервера брокера. Я тестирую на ВТБ, как одном из "тормозных", переключаешь на другой сервер - и уже не так заметно влияние.
 
Цитата
VPM написал:
Просто мысли вслух. Таблицы обезличенных сделок и левел2 это тиковые данные, в то время как  OnParam приходит пакетами примерно раз в секунду. Я кто тому что и очереди и буфер  и тайм фреймы у них ме могут быть одинаковы. OnParam требует индивидуального подхода и подписок на параметры. Может собака в сомой обработке зарыта?
Я довольно редко использую обезличенные сделки и getQuoteLevel2. В данном тесте getQuoteLevel2 просто для создания какой-то нагрузки на qlua API. Простые адекватные расчёты в main не особо влияют.
Тот же ВТБ и без скриптов стартует, да и работает, очень медленно. Я думал Кит - медленный (а там большие потоки данных). Но нет ВТБ выдает результаты в информационном окне типа такого:

средняя задержка данных = 1.877.
Максимальная задержка данных = 29.656.
 
Оставил скрипты тестовые с колбеками запущенными. В итоге:

задержка данных при обмене с сервером = 11.109
средняя задержка данных = 26.384.
Максимальная задержка данных = 175.063

Как только остановил скрипты - побежал счётчик полученных пакетов, отставших записей в информационном окне. И пока данные бегут, то терминал и без скриптов не особо спешит.
 
Цитата
Nikolay написал:
Оставил скрипты тестовые с колбеками запущенными. В итоге:

задержка данных при обмене с сервером = 11.109
средняя задержка данных = 26.384.
Максимальная задержка данных = 175.063

Как только остановил скрипты - побежал счётчик полученных пакетов, отставших записей в информационном окне. И пока данные бегут, то терминал и без скриптов не особо спешит.
Вывод -тормозят Ваши скрипты.
Измерьте время их исполнения.
------------------
Кроме того, тормозит сервер брокера . И это не зависит от скриптов.
Последнее время  у Сбера видны задержки в выставлении заявок
Т е уходит заявка из терминала а в стакане она появляется с заметной задержкой визуально.  
Так как задержка реакция нашего глаза  не менее 0.2 сек то можно говорить что заявка выставляется с задержкой сотни миллисекунд.
------------------------  
Объяснить это можно лишь задержкой на стороне сервера.
Два варианта
1) Умышленная задержка на стороне сервера.
2) Большие очереди заявок.
-------------------------------------  
Но так как эта задержка существует и при спокойном рынке, то скорее всего это 1 вариант
 
 
Цитата
Nikolay написал:
Тест был направлен не на измерение скорости работы скрипта, а на влияние работы скрипта на работу терминала, его интерфейса в первую очередь. Какой смысл показать, да ещё на демо, что main работает быстро.
У меня на демо тоже всё прекрасно. Переключаешься на реальный и во время  открытия рынка - терминал вкладки переключает по 30 секунд.  Была бы возможность инструментально измерить работу самого терминала - так и вопросов не было бы.
Вы не поняли мой тест.
Тест проверяет быстродействие выполнения колбеков, включая обработку очереди .
 
Цитата
nikolz написал:
Вывод -тормозят Ваши скрипты.
Измерьте время их исполнения.
------------------
Но так как эта задержка существует и при спокойном рынке, то скорее всего это 1 вариант
Тексты скриптов выложены выше. Что там конкретно приводит к "тормозам"? Просто интересно, раз такое категоричное утверждение.

Цитата
nikolz написал:
Тест проверяет быстродействие выполнения колбеков, включая обработку очереди .
У меня и не было задачи проверять работу колбеков, а влияние их наличия на скорость работы интерфейса терминала. Буду рад если предложите другой инструментальный тест.  
 
Ок. Чтобы наглядно показать как влияют колбеки на работу терминала запустил такой тест.

Запускаем скрипты, в которых есть только колбек OnParam с одной строкой внутри getParamEx(class_code,  sec_code, 'LAST')

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

https://disk.360.yandex.ru/i/TOFhfjD7EHQtfA

Скрипт банальный. Раз в секунду запрашиваем getParamEx. Также для проверки влияния getInfoParam были добавлены запросы в main, но как показало - не влияет. Лог тоже закомментирован.
Если есть колбек OnParam - влияние видно глазами, через скорость изменения данных в информационном окне. Если его нет, то наличие работающего скрипта визуально не заметно.

Судя по всему, вызывается OnParam на каждую пропущенную запись для какого-то служебного поля, что и приводит к такому. Но это просто догадка. Если так, то это совсем не корректно.

Отдельно также можно сказать, что если не было соединения достаточно долго, то брокер кидает OnCleanUp (это видно по логу и по параметру "число записей" в информационном окне, он скидывается в 0), судя по всему, срабатывает условие "смена сессии". И в итоге загрузка данных происходит долго, очень долго. По крайней мере у ВТБ. Другие бырокеры побыстрее.

Наблюдая за инфомационнгым окном у ВТБ - достатоно часто видно как бежит число "отставшая запись" и в это время терминал занят этим и будет такое же влияние.
Код
local path = _G.getScriptPath()
package.path = path.."/?.lua;"

local bl1 = require('big_lib')
local bl2 = require('big_lib2')
local bl3 = require('big_lib3')
local bl4 = require('big_lib4')

local id = 'script3'
local logFile

local function log_tostring(...)
  local args = table.pack(...)
  if args.n == 1 then
    return tostring(args[1])
  end
  for i = 1, args.n do
    args[i] = tostring(args[i])
  end
  return table.concat(args, " ", 1, args.n)
end

local function log(...)
    if logFile==nil then return end
    logFile:write(log_tostring(...).."\n");
    logFile:flush();
end


local sec_list      = {
    {'SPBFUT', 'MMU6'},
    {'SPBFUT', 'SiU6'},
    {'SPBFUT', 'RIU6'},
    {'SPBFUT', 'USDRUBF'},
    {'SPBFUT', 'CNYRUBF'},
    {'TQBR', 'SBER'},
    {'TQBR', 'GAZP'}
}

local last_data = {}


local rev_lis = {}
for i = 1, #sec_list do
    rev_lis[sec_list[i][2]] = i
    last_data[sec_list[i][2]] = {}
end

local sleep         = _G.sleep
local isRun         = true

local t_id          = nil

-- local SeaGreen      = 12713921  --  RGB(193, 255, 193) нежно-зеленый
-- local RosyBrown     = 12698111  --  RGB(255, 193, 193) нежно-розовый
-- local GetCell       = _G.GetCell
-- local Highlight     = _G.Highlight
local SetCell           = _G.SetCell
local getParamEx        = _G.getParamEx
local getInfoParam      = _G.getInfoParam
local IsWindowClosed    = _G.IsWindowClosed

local Queue = {}
Queue.__index = Queue

function Queue.new()
   return setmetatable({first = 1, last = 0 }, Queue)
end
---  Записать в очередь --
function Queue:push(v)
   if v == nil then error('!!! Ошибка. Параметр v функции QueuePush nil') end
   local last = self.last + 1
   self[last] = v
   self.last = last
   return last - self.first + 1    -- количество элементов в очереди ---
end
---  Читать очередь  --
function Queue:pop()
   local  first =  self.first
   if  first > self.last then return nil   end
   local v, v1  =  self[first], self[first + 1]
   self.first = first + 1
   self[first] =  nil
   v1 = type (v1) == 'string' and #v1 or 0
   return  v, v1   -- v1 -длина следующего элемента (если строка) ---
end

-- Текущий размер очереди ---
function Queue:size()
   return self.last - self.first + 1
end

local queue = Queue.new()

local function process_queue()
    local n = 0
    local res = queue:pop()
    while res do
        n = n + 1
        local last_price = res[3]
        -- local lp = GetCell(t_id, 1, 0).value or last_price
        -- if lp < last_price then
        --     Highlight(t_id, 1, 0, SeaGreen, 0, 500)
        -- elseif lp > last_price then
        --     Highlight(t_id, 1, 0, RosyBrown, 0, 500)
        -- end
        SetCell(t_id, rev_lis[res[2]], 1, tostring(last_price), last_price)
        -- log(id, ' --- set pop value',  n, rev_lis[res[2]], last_price)
        res = queue:pop()
    end
    return n
end

local function GetPrice(class_code,  sec_code)
    local last_price = tonumber((getParamEx(class_code,  sec_code, 'LAST') or {}).param_value) or nil
    if last_data[sec_code][1] == last_price then return end
    local res = {}
    res.last_time  = tonumber((getParamEx(class_code,  sec_code, 'TIME') or {}).param_value) or 0
    if res.last_time == 0 then return end
    res.last_price = last_price
    if not res.last_price then return end
    local bid_depth  = tonumber((getParamEx(class_code,  sec_code, 'BIDDEPTHT') or {}).param_value) or 0
    res.best_bid   = bid_depth > 0 and tonumber((getParamEx(class_code,  sec_code, 'BID') or {}).param_value) or nil
    local ask_depth  = tonumber((getParamEx(class_code,  sec_code, 'OFFERDEPTHT') or {}).param_value) or 0
    res.best_ask   = ask_depth > 0 and tonumber((getParamEx(class_code,  sec_code, 'OFFER') or {}).param_value) or nil
    -- res.last_rec   = tonumber((tostring(getInfoParam('LASTRECORDTIME') or ''):gsub(':', ''))) or 0
    -- res.local_time = (tonumber((tostring(getInfoParam('LOCALTIME') or ''):gsub(':', ''))) or 0)
    -- res.time_diff  = math.abs(res.local_time - res.last_rec) + 10
    last_data[sec_code][1] = last_price
    queue:push{class_code,  sec_code, last_price}
end

local function event_callback(_, msg, par1, par2)
    if (msg == _G.QTABLE_CLOSE) then
        isRun = false
    end
    if msg == _G.QTABLE_CHAR then
        SetCell(t_id, par1, 2, tostring(par2), par2)
    end
end

local function CreateTable()

    t_id = _G.AllocTable()

    _G.AddColumn(t_id, 0, "sec", true, _G.QTABLE_STRING_TYPE, 15)
    _G.AddColumn(t_id, 1, "price", true, _G.QTABLE_DOUBLE_TYPE, 15)
    _G.AddColumn(t_id, 2, "edit", true, _G.QTABLE_DOUBLE_TYPE, 15)
    _G.CreateWindow(t_id)
    _G.SetWindowPos(t_id, 90, 120, 470, 300)
    for i = 1, #sec_list do
        _G.InsertRow(t_id, i)
        SetCell(t_id, i, 0, sec_list[i][2])
    end
    _G.SetTableNotificationCallback(t_id, event_callback)
end

function _G.OnParam(class_code,  sec_code)
    local last_price = tonumber((getParamEx(class_code,  sec_code, 'LAST') or {}).param_value) or nil

   -- if rev_lis[sec_code] then
      -- GetPrice(class_code,  sec_code)
   -- end
end

local last_rec, last_time, time_diff


function _G.main()

    CreateTable()

    logFile = io.open(path.."\\load_"..id..".txt", "w")

    local lt = 0
    local req_int = 1

    while isRun do

        local cwt = os.time()
        if cwt - lt > req_int then
            lt = cwt
            for i = 1, #sec_list do
                GetPrice(sec_list[i][1], sec_list[i][2])
            end
        end

   last_rec   = tonumber((tostring(getInfoParam('LASTRECORDTIME') or ''):gsub(':', ''))) or 0
   local_time = (tonumber((tostring(getInfoParam('LOCALTIME') or ''):gsub(':', ''))) or 0)
   time_diff  = math.abs(local_time - last_rec) + 10

        -- log(id, 'Enter main loop')
   IsWindowClosed(t_id)
        local n = process_queue()
        bl1.func1()
        bl2.func100()
        bl3.func200()
        bl4.func300()
        -- log(id, 'Exit main loop', 'in queue', n)
        -- log('---------------------------------------------------------------------------')
        sleep(60)
    end
end

function _G.OnStop()
    isRun = false
    if t_id and not IsWindowClosed(t_id) then
        _G.DestroyTable(t_id)
    end
end
Страницы: Пред. 1 2
Читают тему
Наверх