До каких пор живёт таблица, передаваемая функции?

Страницы: 1
RSS
До каких пор живёт таблица, передаваемая функции?
 
Пытаюсь перенести обработку OnQuote и OnAllTrade в поток main. C OnAllTrade приходит ссылка на таблицу alltrade:
Код
function OnAllTrade(alltrade)
Сама таблица alltrade находится в стеке вызова этого коллбэка (очевидно, в стеке тоже ссылка, а сама таблица ещё где-нибудь?)

Если я эту ссылку на alltrade помещу в очередь и выйду из OnAllTrade, то не получится ли так, что после выхода из OnAllTrade эта таблица окажется мусором?

Аналогичный вопрос с OnQuote, которая вызывает getQuoteLevel2 и помещает возвращаемую ей таблицу (ссылку на неё) в ту же очередь для обработки в main.

Мне что, перед выходом из этих функций отключать сборку мусора, а после обработки всей очереди в main опять включать??
 
Смутно помнится, в документации на lua.org я видел, что жизнь таблицы из параметров функции гарантируется до выхода из этой функции (т.е. до выхода из OnAllTrade). Какая-то ерунда пока получается с этим переносом обработки таблиц в поток main...
 
Объекты живут, пока на них есть ссылки. Покуда слот в очереди указывает на эту таблицу, она жива.
 
Цитата
funduk написал:
Объекты живут, пока на них есть ссылки.
Похоже, что всё хорошо: переделал скрипт, чтобы он обрабатывал очередь от коллбэков в main, всё работает.
 
Работает, но память, занимаемая скриптом, понемногу растёт, хотя, я после обработки в main таблиц из очереди записываю на место ссылок на них false.

И на мой сегодняшний вопрос в https://forum.quik.ru/forum10/topic8600/ так никто и не ответил, видно, не знают, что сказать...  :what:  
 
Цитата
Serge123 написал:
Смутно помнится, в документации на lua.org я видел, что жизнь таблицы из параметров функции гарантируется до выхода из этой функции (т.е. до выхода из OnAllTrade). Какая-то ерунда пока получается с этим переносом обработки таблиц в поток main...
Жизнь локальных параметров прекращается с выходом из функции.
А таблица, которую Вы передали через фактические параметры в функцию создана вне этой функции.
поэтому она будет утилизирована лишь когда на нее не будет ссылок вообще.
Когда вы ее указатель помещаете в очередь, а очередь существует вне функции, то таблица живет своей жизнью и дальше.
 
getQuoteLevel2 лучше вызывать в main, чтобы не тормозить основной поток.
 
Цитата
nikolz написал:
getQuoteLevel2 лучше вызывать в main, чтобы не тормозить основной поток.
У Вас есть какой-нибудь скрипт, подтверждающий это?

Я когда дампил квик через procdump, постоянно видел, что вызовы qlua (типа SetEmptyCallback) из main стояли на входе в критическую секцию, а вот вызовы из главного потока - никогда.
 
Интересно: как можно проверить, что мой вариант скрипта, в котором я перенёс обработку стаканов и обезл. сделок в main, имеет смысл? Мне кажется, что добавилось лишней работы в потоке main с разбором очереди, а в потоке Квика работа уменьшилась неощутимо...
 
Цитата
funduk написал:
Цитата
nikolz написал:
getQuoteLevel2 лучше вызывать в main, чтобы не тормозить основной поток.
У Вас есть какой-нибудь скрипт, подтверждающий это?

Я когда дампил квик через procdump, постоянно видел, что вызовы qlua (типа SetEmptyCallback) из main стояли на входе в критическую секцию, а вот вызовы из главного потока - никогда.
Это написано в документации.
Могу объяснить на коде почему это так.
-----------------
Кроме того, если эта таблица создана глобально, то она будет всегда, если вы явно не присвоите ей nil.
------------------
Проверить можно на СИ.
Могу рассказать как.
 
Пардон, ответил не на тот вопрос.
 
Цитата
Serge123 написал:
Интересно: как можно проверить, что мой вариант скрипта, в котором я перенёс обработку стаканов и обезл. сделок в main, имеет смысл? Мне кажется, что добавилось лишней работы в потоке main с разбором очереди, а в потоке Квика работа уменьшилась неощутимо...
Вы правильно мыслите.
Если хотите получить эффект, то надо убирать sleep и  использовать event.
 
Цитата
funduk написал:
Цитата
nikolz написал:
getQuoteLevel2 лучше вызывать в main, чтобы не тормозить основной поток.
У Вас есть какой-нибудь скрипт, подтверждающий это?

Я когда дампил квик через procdump, постоянно видел, что вызовы qlua (типа SetEmptyCallback) из main стояли на входе в критическую секцию, а вот вызовы из главного потока - никогда.
Вес функции qlua в основном стеке.
Основной стек в главном потоке.
стек main - это дополнительный стек.
колбеки блокируют доступ main к  глобальному стеку.
Поэтому вызов функций qlua в колбеках не требует дополнительной синхронизации. Ее уже сделали при вызове колбека  
 
и еще...
Я как-то выкладывал результаты теста, в котором видно, что колбеки тормозят  main поток.
 
Serge123,
Относительно очистки памяти при выходе из функции или удалении таблицы,
-----------------
Сборщик мусора работает по определенному алгоритму у которого есть настраиваемые параметры.
-------------------
Чтобы увидеть уменьшение занятой памяти надо запустить сборщик принудительно.
пример:
Код
local M=10000000
local t={}
count1 = collectgarbage("count") print("объем занятой памяти",count1//1);
for i=1, M do t[i]=i end
count1 = collectgarbage("count") print("объем занятой памяти массивом",count1//1);
t=nil  -- удаляем массив
count1 = collectgarbage("count") print("объем занятой памяти после удаления массива ",count1//1);
collectgarbage("collect") count1 = collectgarbage("count") print("объем занятой памяти после сборщика массива ",count1//1);
os.exit()



результат:
Код
>D:/lua53/lua53.exe -e "io.stdout:setvbuf 'no'" "Test.lua" 
объем занятой памяти   58.0
объем занятой памяти массивом   262202.0
объем занятой памяти после удаления массива    262199.0
объем занятой памяти после сборщика массива    50.0
>Exit code: 0
 
nikolz, ну вот да, поэтому у меня и вопрос, что больше тормозит главный поток квика -- вызов qlua функций из колбэков или из main с синхронизацией. Если число таких вызовов одинаково (что бывает, если main обрабатывает данные быстрее, чем они поступают), должно получиться, что тормозить больше будут вызовы из main, потому что число синхронизаций вырастет. Если же main не успевает за колбэками, и можно не все данные колбэков обрабатывать, то вызов qlua в main может быть быстрее, чем в колбэках, просто потому, что вызовов будет меньше, но накладные расходы на синхронизацию могут всё равно свести преимущество на нет. Поэтому и вопрос был, есть ли у Вас тест на это.
 
Цитата
funduk написал:
nikolz, ну вот да, поэтому у меня и вопрос, что больше тормозит главный поток квика -- вызов qlua функций из колбэков или из main с синхронизацией. Если число таких вызовов одинаково (что бывает, если main обрабатывает данные быстрее, чем они поступают), должно получиться, что тормозить больше будут вызовы из main, потому что число синхронизаций вырастет. Если же main не успевает за колбэками, и можно не все данные колбэков обрабатывать, то вызов qlua в main может быть быстрее, чем в колбэках, просто потому, что вызовов будет меньше, но накладные расходы на синхронизацию могут всё равно свести преимущество на нет. Поэтому и вопрос был, есть ли у Вас тест на это.
Рассмотрим два варианта
В первом колбек читает стаканы  и помещаются в очередь их вместе с clas и sec.
main читает стаканы из очереди, при этом main еще читает из очереди clas и sec.
--------------------
Во втором колбек помещает в очередь clas и sec
main  читает clas и sec и  если надо, то читает стаканы.
---------------------
Полагаю, что второй вариант бесспорно лучше.
Второй вариант будет еще в разы лучше,
если вместо sleep использовать event.
--------------------
что не так?
 
Serge123,
Придумал лишь одно объяснение Вашему примеру, где не изменяются ни время ни цена.
Это возможно в режиме договорной сделки.  
Когда через биржу один крупный игрок продает конкретно другому игроку большой объем, например, сделка РЕПО.
Но это лишь мое предположение.
------------------
 
Цитата
nikolz написал:
что не так?
не хватает только теста под реальной нагрузкой для учёта эффекта синхронизаций
 
Цитата
funduk написал:
Цитата
nikolz написал:
что не так?
не хватает только теста под реальной нагрузкой для учёта эффекта синхронизаций
Пока не придумал. Есть варианты алгоритма теста?
 
Цитата
nikolz написал:
Есть варианты алгоритма теста?
Я провёл тест, который не выявил разницы. Может быть, getQuoteLevel2 не нужна синхронизация? Запустил два почти одинаковых скрипта, рисующих стакан каждый в своём потоке (настроено так, чтобы гуи рисовался в main скрипта, а не в главном потоке квика). Ниже часть кода одного из скриптов с комментами про замены, чтобы получить второй скрипт. Единственная стабильная разница, что вызов в main даёт на 1 секунду больше CPU time, хотя этот скрипт был запущен на 4 секунды позже (запускал в дневной клиринг, как видно на скрине, чтобы не было обновлений стакана на срочке)

Код
local cols, qt
local sent, received, updates = 0, 0, 0
function OnQuote(class_code, sec_code)
  -- отслеживаем котировки только по указанному инструменту
  if (class_code ~= CLASS) or (sec_code ~= SEC) then
    return
  end
  qt = getQuoteLevel2(class_code, sec_code) -- во втором скрипте убрать эту строку
  sent = sent + 1
end

local fmt = string.format
local function updateGrid()
  local s = sent
  if received < s then
    received = s
    fillCols(qt) -- во втором скрипте заменить на fillCols(getQuoteLevel2(CLASS, SEC))
    updates = updates + 1
    grid:BeginUpdate()
    colors = cols.colors -- cols заполняется внутри fillCols, colors используется при рисовании стакана внутри grid.OnPrepareCanvas (не показано тут)
    grid:SetCells(0,1,s) -- число вызовов OnQuote
    grid:SetCells(0,2,updates) -- число отрисовок стакана
    grid:SetCells(0,3,fmt('%.1f%%',(1-updates/s)*100)) -- процент потерь обновлений OnQuote
    local m,ti,mti = VCL.IsMultiThread()
    grid:SetCells(0,4,tostring(m)) -- System.isMultiThread
    grid:SetCells(0,5,tostring(ti)) -- ThreadId
    grid:SetCells(0,6,tostring(mti)) -- MainThreadId
    for c = 0,2 do
      for r,str in pairs(cols[c]) do
        grid:SetCells(c,r,str)
      end
    end
    grid:EndUpdate()
  end
end

is_run = true
function main()
    CreateAndShow()
    while is_run do
        sleep(1)
        updateGrid()
        app:ProcessMessages()
    end
end
 
Цитата
funduk написал:
Цитата
nikolz написал:
Есть варианты алгоритма теста?
Я провёл тест, который не выявил разницы. Может быть, getQuoteLevel2 не нужна синхронизация? Запустил два почти одинаковых скрипта, рисующих стакан каждый в своём потоке (настроено так, чтобы гуи рисовался в main скрипта, а не в главном потоке квика). Ниже часть кода одного из скриптов с комментами про замены, чтобы получить второй скрипт. Единственная стабильная разница, что вызов в main даёт на 1 секунду больше CPU time, хотя этот скрипт был запущен на 4 секунды позже (запускал в дневной клиринг, как видно на скрине, чтобы не было обновлений стакана на срочке)
Код
  
Мы с Вам о принципиально разных решениях говорим.
--------------------------------------
В вашем тесте - один инструмент, стакан которого вы рисуете.
В этом случае Вы не заметите разницы,
так как вызов функции getQuoteLevel2 существенно меньше рисования стаканов.
==============  
Моя постановка задачи для теста такая.
----------------------
Торгуется портфель инструментов.
Поток main работает по событиям.
Все события формируют очередь(может быть несколько очередей)
----------------
1) В этом случае, если  getQuoteLevel2  вызывать в колбеке, то в очередь попадет весь стакан и clas и sec.
Т е время работы колбека всегда будет включать запрос стакана.
=========
2) Если в колбеке не запрашивать стакан, то в очередь запишется clas и sec.
Т е время работы колбека будет меньше всегда, чем в первом случае.
--------------------
В main будет вызываться функция getQuoteLevel2 .
Она находится в глобальном стеке и обращение к ней уже синхронизировано в библиотеке QLUA.
Но так как к ней никто вне main не обращается, то ее вызов не будет ничего тормозить и ничего блокировать не надо.
------------------
Если рынок очень активен,
то в первом варианте Вы получите целую толпу стаканов, которые уже устарели.
---------------------
Во втором варианте в очереди будет всего один колбек и в main будет прочитан самый последний стакан.
--------------------
У меня робот работает именно так.
 
Цитата
nikolz написал:
так как вызов функции getQuoteLevel2 существенно меньше рисования стаканов.
А у Вас обработка сравнима по времени с getQuoteLevel2 и другими необходимыми Вам вызовами qlua? Я тестирую на том, чем сам потом пользоваться буду, для меня пока нет разницы. В очереди для стаканов не вижу смысла, кстати, я просто хэш-таблицу заюзаю с ключами по sec и содержимым sent,updates,received,стакан.
 
Цитата
funduk написал:
Цитата
nikolz написал:
так как вызов функции getQuoteLevel2 существенно меньше рисования стаканов.
А у Вас обработка сравнима по времени с getQuoteLevel2 и другими необходимыми Вам вызовами qlua? Я тестирую на том, чем сам потом пользоваться буду, для меня пока нет разницы. В очереди для стаканов не вижу смысла, кстати, я просто хэш-таблицу заюзаю с ключами по sec и содержимым sent,updates,received,стакан.
Обработка сравнима.
Создаю потоки из пула системных потоков и в них запускаю Luajit (из всего, что пробовал это быстрее всех работает).  
В указанном ранее тесте в отдельные моменты создавалось максимум 11 потоков.
------------------  
Я не рисую стаканы. Скальпингом не занимаюсь.  
Использовал стакан при реализации алгоритма закрытия позиции по стопу.  
Но в основном использую либо лучшие предложения либо по рынку, так как торгую лишь ликвидными акциями.
Страницы: 1
Читают тему
Наверх