Хм. При исполнении кода без sleep не то что колбеки не вызываются, а вообще терминал намертво зависает. 8.13.0
Код
i = 1e5
run = true
function OnStop ( )
message ( "OnStop" )
run = false
return 5000
end
--sleep = function ( ) end
function main ( )
while run and i > 0 do i = i - 1; sleep ( 0 ) end
message ( tostring ( i ) )
end
Владимир, колбеки из главного треда, как в инструкции написано. Может я инструкцию неправильно понял?
Цитата
Во время выполнения функции main() Lua скрипт не мешает работе основного функционала РМ QUIK, таким образом, внутри функции main() использование функции sleep() не приводит к «подвисанию» РМ QUIK
При использовании событийной модели Lua скрипт выполняется в двух потоках: функции обратного вызова выполняются в основном потоке РМ QUIK, а функция main() в дополнительном потоке РМ QUIK
А тут у нас подвисание если НЕ использовать sleep() в main(), и события не приходят.
Артем, Да, Вы неправильно поняли. До знакомства с Квиком я и в страшном сне не мог себе представить, что ИНТЕРПРЕТИРУЕМЫЙ код способен подвесить комп, и даже пытался спорить с Антоном. Я был неправ - нет ничего невозможного для нынешнего состава создателей софта! Кстати, реализация "многопоточности" здесь столь же идиотская.
i = 1e8
s = ""
function OnStop ( )
i = -i
s = s .. " stop "
return 5000
end
function main ( )
-- sleep = function ( ) end
while i > 0 do i = i - 1; s = "before "; sleep ( 0 ) s = s .. " after" end
message ( s )
end
Колбеки дёргаются внутри sleep(). Я помнится говорил что можно так сделать, не знаю было ли уже так сделано к тому моменту. То что весь скрипт работает в одном потоке это хорошо. Теперь осталось отсоединить этот поток от главного треда QUIK. Впрочем Старатель вроде как поймал всю ту же старую ошибку с разрушением стека, может где-то что-то пытается прервать тред скрипта. С многопоточностью в скриптовых языках конечно есть только один надежный подход - не иметь её, на каждый тред создавать отдельную виртуалку.
Артем, Колбеки дёргаются внутри sleep() - и это НОРМАЛЬНО! Фактически sleep есть инструкция интерпретатору: "Скрипт спит - займись чем-нибудь полезным". У меня именно ВЕСЬ скрипт работает в одном потоке (кроме OnTrade, OnStop и обработчиков событий, повешенных на SetTableNotificationCallback). По-нормальному, там надо бы только проставить какие-то флаги, и обрабатывать их тоже в том же потоке, но этот козёл теряет управление, так что на код OnStop стыдно смотреть. А что делать? Код ужасен, но он, по крайней мере, РАБОТАЕТ! А на стеки, треды и прочую хрень - плевать. Пишем на девственно чистом Lua!
Таки нет. Колбеки приходят когда им удобно. При этом тред скрипта может прерываться в любой точке либо не прерываться вообще (с зависанием QUIK) по велению левой пятки хоста и оптимизатора байткода.
Судя по всему в примере просто sleep(0) занимает больше всего времени и вероятность что колбек выпадет в этот момент наивысшая.
Владимир, кстати вынужден согласиться что здесь колбеки действительно работают как прерывания. Когда я спорил по этому вопросу я допустил ошибку, что предрассудил будто в QUIK используется такая же простая и адекватная система многопоточности скриптовых языков как и во всём остальном мире.
Старатель написал: Volume[alltrade.price] = (Volume[alltrade.price] or 0) + alltrade.qty
1. Все операторы в QLua (включая функции, запускаемые в колбеках), в том числе с участием атомарных C-функций (выдающих однозначный результат в контексте их запуска), являются атомарными. 2. Взаимодействие колбеков с main подробно обсуждалось в ветке «Грядущие изменения на срочном рынке МБ: поддержка работы с 19-значными номе-рами заявок и сделок» и Антон там достаточно детально это описал.
Наверное, стоит пояснить, что же представляет собой контекст выполнения функции. Это все, от чего зависит ее результат. А это, в некоторых случаях не только явно задаваемые ее параметры, но и среда, в которой она выполняется. Например, результат файловой операции зависит не только от ее параметров, но и от состояния, в котором находится файл. Если не учитывать остальной контекст файловой операции, а только ее параметры, то можно бы было сказать, что эта операция неоднозначная (при одних и тех же параметра результат может быть разным). При учете всего контекста файловая операция однозначная. Если бы вы работали без операционной системы (ОС), то в контекст выполнения ваших функций входило бы и все то, чем занимается ОС (прерывания, параллельно работающие ядра ЦП и т.д). На самом деле, корректно реализованные средства разработки программ, в том числе и QLua, локализуют (уменьшают) тот контекст, от которого зависят пользовательские функции. В QLua, в той реализации как он сейчас есть и в том виде как его используют большинство пользователи (main и колбеки), по существу является однопоточным. А если это так, то, при корректной реализации QLua, проблемами параллелизма (в том числе атомарностью) можно было бы не озадачиваться.
Артем, Колбеки-то пусть приходят когда им удобно. Но какая, в жопу, разница, ЧЕМ при этом занимается скрипт? Это же ПРЕРЫВАНИЯ!
Ну, хорошо: вот Вам задачка на сообразительность: я недавно где-то писал, что у меня целых три прерывания по таймеру, и самое быстрое из них (я пробовал для него значения 150, 300, 500, 1000, 1500 миллисекунд, остановился на 300) предназначено для обслуживания действий юзера (мышка, клава). Вопрос: ЗАЧЕМ я это делаю, если на действия юзера приходят именно "колбеки когда им удобно", а обработчики эти устанавливаются по SetTableNotificationCallback? ПРИ ЧЁМ тут вообще таймер, да ещё и самый быстрый?
TGB, Согласен, "QLua по существу является однопоточным", а потому всей этой фигнёй с "проблемами параллелизма (в том числе атомарностью)" не следует озадачиваться.
Владимир написал: у меня целых три прерывания по таймеру
Все sleep, запускаемые в main, с любыми интервалами, будут выполняться последовательно. И мне стало интересно, что вы понимаете под прерыванием по таймеру (надеюсь это не аппаратные прерывания:smile: ). Поэтому, с этого места, пожалуйста, опишите поподробнее. Тела ваших циклов меня не интересуют, но схему их организации вы, наверное, смогли бы привести.
TGB, Разумеется, sleep там один (тот, который сейчас 300 мс). В цикле main вызывается именно этот, самый быстрый обработчик. А на каждые 5 срабатываний этого обработчика вызывается другой, полуторасекундный. А на каждые 10 срабатываний того... короче, всё очень просто: пара счётчиков - и нет проблем. У меня даже три счётчика: 15-секундный, помимо прочего, используется ещё и для снятия несработавших заявок через 5 минут.
TGB, Подобную реакцию я здесь уже видел (в разговоре с Антоном, кажется). На что отвечал примерно так: "Алгоритмически это именно прерывания, поэтому мне удобнее называть их именно так".
Старатель написал: Тогда это тоже атомарная операция:
Код
Volume[alltrade.price] = (Volume[alltrade.price] or 0) + alltrade.qty
Проверил в Lua 5.1. Скрипт:
Скрытый текст
Код
local a = {}
function OnInit()
for i = 1, 100000 do a[i] = 1 end
end
local run = true
function OnStop()
a = nil
run = false
end
function OnAllTrade()
a = nil
run = false
end
function OnParam()
a = nil
run = false
end
function main()
local r
run = true
a[0]=(a[1]or 0)
+ (a[2]or 0)
+ (a[3]or 0)
... -- Тут много строк "+ (a[i]or 0)"
+ (a[99999]or 0)
+ (a[100000]or 0)
r = run
message(tostring(r) .. '; ' .. a[0], 2)
end
И получил ошибку типа
Цитата
16492: attempt to index upvalue 'a' (a nil value)
Т.е., в Lua 5.1 лок может быть снят в процессе извлечения значения из таблицы. Т.ч., как сказал Антон:
Цитата
Anton написал: Вероятность, что в версии луа 55.99 станет неатомарным - есть.
Также в Lua 5.1 при выполнении байт-кода блокировка может быть снята в таких местах:
Код
a = b + c
-- тут блокировка может быть захвачена другим потоком
x = y - z
Стоит также отметить, что в Lua 5.1 байт-код выполняется значительно дольше по сравнению с 5.4. Возможно как раз из-за постоянной борьбы за блокировку между потоками.
Надо делать так, как надо. А как не надо - делать не надо.
s_mike@rambler.ru написал: Вот такой вариант. Но не в таблицу выводит, а рисует на графике.
s_mike@rambler.ru, как вы рисуете прямоугольники на графике через qlua? Как привязаться к временным меткам (например, от свечи С1 до свечи С2) или работаете через пиксели?
s_mike@rambler.ru написал: Вот такой вариант. Но не в таблицу выводит, а рисует на графике.
s_mike@rambler.ru, как вы рисуете прямоугольники на графике через qlua? Как привязаться к временным меткам (например, от свечи С1 до свечи С2) или работаете через пиксели?
метки. Других инструментов нам qlua не предоставляет.
Как привязаться к временным меткам - так время свечей нам доступно... Если я правильно понимаю вопрос.
Скажем |||||||||||||||||||||||||||||||| мелким шрифтом будет выглядеть как линия. Но вот длину придется подбирать опытным путем, т.к. у метки есть только одна координата - начало.
s_mike@rambler.ru написал: Как привязаться к временным меткам - так время свечей нам доступно... Если я правильно понимаю вопрос.
это я понял.
не понятно ка нарисовать линию: QLua
Код
line_id_1 = line(Point(x1,y1), Point(x2,y2)); // как это сделать
Вы про низкоуровневое рисование по пикселам? В отличие от современных терминалов и программ технализа наш бронтозавр не предоставляет средств низкоуровневого рисования. Можно самому извращаться с winapi, это тупиковая история.
Единственные координаты, что мы имеем - это время и цена без возможности пересчеты в актуальные пикселы окна. Лет N назад, где N примерно равно 10, эта тема обсуждалась, помнится разработчик меня даже просил прислать список средств рисования mt5 и Amibrooker (гугл с яндексом в арке под запретом?) но результат мы знаем.
s_mike@rambler.ru написал: Вы про низкоуровневое рисование по пикселам?
Я хотел спросить как вы нарисовали горизонтальные объемы здесь или прямоугольники здесь? Как задавали точки начала (это наверное понято - по меткам) и конца (вот это не понятно). Я хочу в итоге нарисовать прямоугольник между несколькими свечами с заданной высотой. Вот не могу понять как задать координаты.