Столкнулся с проблемой при работе с тиками через CreateDataSource.
Запускаешь квик, таблица обезличенных сделок пока пустая (удалить alltrade.dat для воспроизведения), квик начинает быстро грузить сделки. В это время работает мой скрипт, который берет данные тиков, например ds:T(i), ds:V(i). Скрипт падает в ошибку: Critical error ACCESS_VIOLATION in script C:\LuaScripts\TestQuikLua\test_ds5.lua Ошибка возникает во второй половине дня, когда новых тиков много и квик долго их прокачивает. Т.е. проблема когда квик активно закачивает сделки и скрипт работает с DataSource. Воспроизводится в 8.5.2 и 8.6. До версии 8.5 данной проблемы не было.
Код скрипта для воспроизведения:
Код
is_run = true
function main()
message("start", 1)
while is_run do
TestDS("RIM0")
sleep(10)
end;
end
function OnStop()
message("stop", 1)
is_run = false
end
function TestDS(tiker)
local ds, errorDescr = CreateDataSource("SPBFUT", tiker, 0)
local size = ds:Size()
for i = 0, size do
local time = ds:T(i)
end
message("DS " .. tiker .. " " .. size, 0)
end
Наглядное пособие "как прострелить себе ногу". Вы в цикле каждые 10мс создаете новый датасорец и потом внутри в еще одном цикле весь его просматриваете. Удивительно не то, что в 8.5.2 и далее крэшится, удивительно, что раньше не крэшилось.
Это был тестовый пример для воспроизведения, рабочий код другой, и там вызывается намного реже код подсчета, но при этом падает. Можно и один раз создать DataSource и все равно падает.
Код
is_run = true
function main()
message("start", 1)
local ds, errorDescr = CreateDataSource("SPBFUT", "RIM0", 0)
while is_run do
TestDS(ds)
sleep(10)
end;
end
function OnStop()
message("stop", 1)
is_run = false
end
function TestDS(ds)
local size = ds:Size()
for i = 0, size do
local time = ds:T(i)
end
message("DS " .. size, 0)
end
Какой бы из вариантов не использовался, если запуск скрипта ведёт к падению терминала -- это хороший способ указать его разработчикам, где ошибка. Неоптимальные скрипты в этом смысле хороши, что напрягают систему и выявляют ошибки гораздо быстрее. Терминал же всегда должен без ACCESS_VIOLATION работать при синтаксически корректном коде скрипта.
_sk_ написал: Терминал же всегда должен без ACCESS_VIOLATION работать при синтаксически корректном коде скрипта.
Он ловит этот акцесс виолейшен, останавливает скрипт и показывает эту ошибку, так что в этом смысле все ок. А вот что этот акцесс виолейшен там есть (а он есть, проверил), это косячок-с. Случается на доступе к ds:T(i) непосредственно после подключения. Очевидно, после подключения датасорец очищается и начинает заполняться заново, в итоге скрипт лезет дальше его конца, поскольку уже сохранил размер до подключения.
Я во всех своих скриптах при доступе к datasource-объектам внутри main применяю примерно такие фрагменты кода, чтобы во время доступа к datasource его содержимое внезапно не изменилось:
Код
local function getRawCandles(ds, maxSize)
local size = 0
local T, O, H, L, C, V = {}, {}, {}, {}, {}, {}
if ds and ds:Size() > 0 then
table.ssort({ 0, 1 }, function(a, b)
local dsSize = ds:Size()
if maxSize == nil then
maxSize = dsSize
end
local count, offset
if dsSize <= maxSize then
count, offset = dsSize, 0
else
count, offset = maxSize, dsSize - maxSize
end
for i = 1, count do
local j = i + offset
T[i] = ds:T(j)
O[i] = ds:O(j)
H[i] = ds:H(j)
L[i] = ds:L(j)
C[i] = ds:C(j)
V[i] = ds:V(j)
end
size = count
return true
end)
end
return { size = size, T = T, O = O, H = H, L = L, C = C, V = V, }
end
Недостатком является блокировка потока коллбэков, что плохо в случае большого количества скриптов и одновременных запросов данных из datasource.
Т.к. данные приходят с сервера (а мгновенно это никто гарантировать не может), то надо ждать загрузки всех данных (всех баров). Да, ошибка бывает когда обращаешься к пустому Size. Правда падать, вроде как, не должен.
Проблема ожидания не только в том, что надо ждать, а в том, что интерфейс не дает возможности понять: а все ли данные приехали. Этот ds:Size() - это уже точно все или мы еще в процессе. Бывало не раз когда Size() уже не 0, но и не последний. Я для себя сделал процедуру, сравнивающую время последней сделк и время последнего бара, чтобы понимать, что уже все загружено. Но и здесь проблема - нету у нас даты последней сделки, есть только время (уже поднимал этот вопрос). Вот и получается, что для "дырявых" малоликвидных инструментов возможны проблемы определения состояния загружены все данные или нет.
_sk_ написал: чтобы во время доступа к datasource его содержимое внезапно не изменилось
Попробовал (по-своему, но тоже под локом), то же самое. По моим представлениям базовые вещи сделаны уровнем ниже, главный поток получает уведомления оттуда, соответственно лок не дает ему это уведомление получить, но само действие таки происходит. Поэтому где-то лок помогает (когда данные берутся из таблицы, живущей в главном потоке), где-то нет (когда напрямую из хранилища). Хороший эксперимент - повесить весь юай на локе при подключенном сервере, данные продолжают себе ехать, файлы растут, хотя квик висит намертво.
А теперь хотелось бы увидеть ответ от разработчиков терминала, что они по этому поводу думают.
1) Считается ли проблемой ACCESS_VIOLATION, упомянутый выше?
2) Как пользователям корректно сделать цикл по всем имеющимся данным внутри DataSource, чтобы не нарваться в процессе итерирования на изменение данных из-за поступившей новой рыночной информации или очистки объекта DataSource?
Еще немного потестировал. Падает не только при полной прокачке тиков, но и при получении новых тиков тоже. Запустил квик, дождался когда прокачаются тики и начнут новые тики приходить, запускаю скрипт, через некоторое время падает с этой же ошибкой.
Еще пытался понять на каком i падает, нет зависимости, на разном i падает, в начале, в середине, в конце.
Чисто из головы немного рассуждений. Тиковый датасорец берет данные из таблицы всех сделок, таблица всех сделок мэпится в память блоками по 64к. Когда таблица перерастает очередную границу, мэппинг прибивается и создается новый побольше. Предположение: датасорец лезет в мэппинг, который уже прибит из-за прихода очередного тика, т.е. либо он кэширует указатель, либо это проблема с синхронизацией, когда другой поток начинает пересоздавать мэппинг прямо под лезущим в него потоком скрипта.
Здравствуйте, на версии 8.6.097, проблема с general protection fault с версии 8.5 никуда не исчезла! Продолжает валиться квик на рабочих lua скриптах с версии 7.27.1. Произвольно, иногда при запуске сразу, иногда через небольшое время. Дамп, скрины отправил в поддержку, уже второй раз!
Скрипты поменял, учел изменения в lua 5.3, никаких подключаемых внешних библиотек нет, только код. Отправлять саппорту терминал со всеми скриптами не вариант!
Это же жесть!! Ранее эксперименты с квиком можно было игнорировать, не участвуя в сырой отладке на пользователях, оставаясь на старой версии, а теперь через пару недель запустят изменения на бирже, на версии 7 оставаться, как пишет саппорт нельзя, новая валится, что делать?????
Евгений Петров написал: Здравствуйте, на версии 8.6.097, проблема с general protection fault с версии 8.5 никуда не исчезла! Продолжает валиться квик на рабочих lua скриптах с версии 7.27.1. Произвольно, иногда при запуске сразу, иногда через небольшое время. Дамп, скрины отправил в поддержку, уже второй раз!
Скрипты поменял, учел изменения в lua 5.3, никаких подключаемых внешних библиотек нет, только код. Отправлять саппорту терминал со всеми скриптами не вариант!
Это же жесть!! Ранее эксперименты с квиком можно было игнорировать, не участвуя в сырой отладке на пользователях, оставаясь на старой версии, а теперь через пару недель запустят изменения на бирже, на версии 7 оставаться, как пишет саппорт нельзя, новая валится, что делать?????
Добрый день.
Если вы нам присылали dmp, то Вам должны были обращению присвоить CQ. Если так, то ожидайте ответ.
_sk_ написал: Пока не теряю надежду, что разработчики ответят на поставленные выше вопросы.
Добрый день,
Описанная в данном инциденте ошибка возникает из-за проблемы синхронизации доступа к данным из Lua-скрипта и будет исправлена в одной из ближайших очередных версий программы. Приносим извинения за причиненные неудобства.
_sk_ написал: Пока не теряю надежду, что разработчики ответят на поставленные выше вопросы.
Добрый день,
Описанная в данном инциденте ошибка возникает из-за проблемы синхронизации доступа к данным из Lua-скрипта и будет исправлена в одной из ближайших очередных версий программы. Приносим извинения за причиненные неудобства
mefisto mefisto написал: столкнулся с такой же проблемой. исправление еще не реализовано? если реализовано то с какой версии? у сбербанка последня 8.7.1.3 как раз..
Добрый день.
К сожалению, ошибка еще не исправлена.
Мы сообщим в данной ветке форума, когда выйдет версия с исправленной проблемой.
Андрей написал: Воспроизводится в 8.5.2 и 8.6. До версии 8.5 данной проблемы не было.
----
Андрей написал: тоже падает (Critical error ACCESS_VIOLATION).
----
Евгений Петров написал: на версии 8.6.097, проблема с general protection fault с версии 8.5 никуда не исчезла! Продолжает валиться квик на рабочих lua скриптах с версии 7.27.1. Произвольно, иногда при запуске сразу, иногда через небольшое время.
-------------------------------------- Не буду утверждать стопудово, но многие ситуации в версиях QUIK >= 8.5, скорее всего, связаны с тем, что в этих версиях возникают ошибки реализации АРКОй QLua-машины 5.3.5 (отличной от нативной Lua-машины 5.3.5). Это отличие связано с тем, что QLua-машина 5.3.5 должна быть потокобезопасной, по сравнению с однопоточной Lua-машиной 5.3.5 (о причинах этого можно почитать мой комментарий № 142 по ссылке: https://forum.quik.ru/forum10/topic5119/?PAGEN_1=3). Более определенно, могу утверждать, что мой тест (многопоточный) автоматического управления памятью QLua-машины 5.3.5, для всех существующих (на дату 07.09.20) версий QUIK >= 8.5 диагностирует, в интервале 5 минут (в произвольные моменты), ее сбои (похоже, вызванные ошибками в синхронизации) и утечку памяти. Поддержке QUIK мною, начиная с 25.05.20, выслано более 40 дампов, а 15.08.20 выслан и сам тест для возможности оперативной отладки разработчиками новых версий QUIK. Для версий QUIK < 8.5 этот тест, ошибок не обнаруживает. Представьте себе, что на вашем ПК очень часто сбоит RAM (память). При этом любые ваши программы могут падать в любом месте, и можно искать в них свои ошибки до «посинения» (сам я этим не занимаюсь, до тех пор, пока не будут устранены сбои автоматического управления памятью QLua-машины 5.3.5).
Сегодня тоже первый раз (за все время использования версий > 8.5) словил такую ошибку на 8.8.4.3.
При этом это не тики, а M5, и произошла она на уже загруженных данных. Т.е. это была новая порция, скорее всего. Индекс бара фиксируется в переменной перед чтением.
Скрипт упал, хотя часть кода работы с свечками обернута pcall.
С другой стороны, никакой доп. информации нет, поэтому пока могу предположить, что это именно доступ к барам, как и в примере выше. Но кто знает, что это было на самом деле. Хотелось бы, конечно, чтобы секции pcall давали больше информации.
Кажется, нашел дырочку, через которую квик может падать при ошибке в скрипте. Вышеприведенная функция вызывается со всеми (?) колбеками по одной схеме, примерно так
Код
int top = lua_gettop(pstate);
lua_getglobal(pstate, "CallbackName");
push_callback_arguments(pstate);
if(this->execute_lua_callback(pstate, nargs, 0))
quik->show_message(make_error_text(), 3);
// вот тут интересно
if(pstate)
lua_settop(pstate, top);
Как мы видели выше, при некоторых ошибках квик прибивает скрипт, то есть стейт к моменту вызова lua_settop уже неживой. А проверяется перед вызовом сохраненный локально указатель, который, конечно, как был не-null, так и остался. Возможно, это компилятор наоптимизировал. В каких колбеках ни посмотри - одно и то же.
local sleep = _G.sleep
local isRun = true
function _G.main()
local sec_code = 'SRZ0'
local class_code = 'SPBFUT'
local ds = _G.CreateDataSource(class_code, sec_code, _G.INTERVAL_M5)
if not ds then
isRun = false
end
local index = 0
if isRun then
while isRun do
local last = ds:Size()
if last ~= 0 then
while index < last-1 do
index = index + 1
ds:T(index)
end
ds:Close(last)
ds:T(last)
end
sleep(100)
end
end
end
Он с ошибкой, как у меня было (Close вместо C). Но хотелось бы внятного сообщения, типа - попытка индексировать значение nil.
И еще особенность: скрипт, упавший с этой ошибкой повторно не запустить, кнопка "Запустить" не активна. Приходится удалять и заново добавлять.
При ближайшем рассмотрении оказывается, что мейн тоже вызывается по той же схеме, только из своего потока, для него тоже все в силе.
Цитата
Nikolay написал: Вот схематичный скрипт, падающий с этой ошибкой.
Ну так да, квик лезет куда-то по прибитому указателю и получается акцесс виолешен (уже не в луа, а в самом квике), а он идет мимо pcall, как выше видно.
В учебно-тренировочном хосте с обычным луа 5.3 попробовал генерировать и плюсовые, и seh исключения в скрипте, так их pcall чудесно отлавливает, только что содержательных описаний не выводит, в первом случае "возможно необработанное исключение", во втором просто "объект ошибки не предоставлен". Помнится, раньше квик тоже похожие сообщения выводил в некоторых случаях, то есть ловились они прекрасно pcall'ом. Как теперь получается, что av пролетает мимо pcall, вот вопрос интересный.
Цитата
Nikolay написал: И еще особенность: скрипт, упавший с этой ошибкой повторно не запустить, кнопка "Запустить" не активна. Приходится удалять и заново добавлять.
local sleep = _G. sleep
local isRun = true
function _G.main ()
local sec_code = 'SRZ0'
local class_code = 'SPBFUT'
local ds = _G.CreateDataSource (class_code, sec_code, _G.INTERVAL_M5)
if not ds then
isRun = false
end
local index = 0
if isRun then
while isRun do
local last = ds: Size ()
if last ~ = 0 then
while index < last - 1 do
index = index + 1
ds:T(index)
end
ds: Close (last)
ds:T(last)
end
sleep ( 100 )
end
end
end
Он с ошибкой, как у меня было (Close вместо C). Но хотелось бы внятного сообщения, типа - попытка индексировать значение nil.
И еще особенность: скрипт, упавший с этой ошибкой повторно не запустить, кнопка "Запустить" не активна. Приходится удалять и заново добавлять.
Здравствуйте!
Ваше обращение получено, проблема изучается. Постараемся в ближайшее время дать ответ.
Это не связано с вызовом CreateDataSource. Точно такая же ошибка была получена 25.09.2020 на вызовах OnAllTrade в 10:12:38 (последняя обработанная запись). Инструмент RIZ0. Терминал 8.7.0.6. До этого два или три года на версии 7 скрипт ни разу не зависал. И три или четыре дня, т.е. с 22.09.2020 тоже работал без сбоев, на этом же терминале 8.7.0.6. В Квике выглядит как остановленный скрипт, т.е. с "красным квадратиком". Кнопки "Запустить" и "Остановить" - не активны. Если это поможет, то в main пусто (только цикл для isRun), а прямо в OnAllTrade примерно 15 строчек кода. Вызов CreateDataSource отсутствует.
MG написал: Это не связано с вызовом CreateDataSource. Точно такая же ошибка была получена 25.09.2020 на вызовах OnAllTrade в 10:12:38 (последняя обработанная запись). Инструмент RIZ0. Терминал 8.7.0.6. До этого два или три года на версии 7 скрипт ни разу не зависал. И три или четыре дня, т.е. с 22.09.2020 тоже работал без сбоев, на этом же терминале 8.7.0.6. В Квике выглядит как остановленный скрипт, т.е. с "красным квадратиком". Кнопки "Запустить" и "Остановить" - не активны. Если это поможет, то в main пусто (только цикл для isRun), а прямо в OnAllTrade примерно 15 строчек кода. Вызов CreateDataSource отсутствует.
Добрый день.
Как раз с этим вопросом мы и занимаемся. Как будет результат дадим здесь ответ.
Описанная в данном инциденте ошибка была исправлена в версии 8.9.0 терминала QUIK. Рекомендуем вам обновить версию программы. Приносим извинения за причиненные неудобства.