Изменения в работе с колбеками LUA в новой версии

Страницы: 1 2 След.
RSS
Изменения в работе с колбеками LUA в новой версии
 
Разработчики написали в письме:
Цитата
 В ближайшей версии мы изменим работу с коллбэками Lua. Ожидаем, что изменения исключат возникающую ошибку.  
Могли бы разработчики более подробно описать грядущие изменения?
 
Цитата
Александр написал:
Разработчики написали в письме:
Цитата
 В ближайшей версии мы изменим работу с коллбэками Lua. Ожидаем, что изменения исключат возникающую ошибку.  
Могли бы разработчики более подробно описать грядущие изменения?
Добрый день,
Пока подробностей нет. Как выйдет новая версия это будет указано в списках изменений.
 
Да не будет там изменений, что вы так переживаете. С чего вдруг?
Изменят техническую реализацию - вот и все. Сути никак не поменяет
 
Цитата
swerg написал:
Да не будет там изменений, что вы так переживаете. С чего вдруг?
  Я не знаю точно, какие изменения будут, но попытаюсь дать прогноз (интересно, насколько промахнусь). А если промахнулся, то это мои предложения.

    Видимо это будут изменения, которые надо было внести в схему обработки коллбеков QLua, как мне кажется, давно, а именно:

    1)    вместо регистрации функций обратного вызова, регистрация соответствующих очередей событий (возможно, с теми же именами);  я бы сделал эти очереди циклическими, с указанием их длины при регистрации, но не более некоторого значения;

    2)    вместо sleep, служебная функция ожидания либо истечения интервала времени (как в sleep), либо появления данных в очередях событий (с выдачей списка непустых очередей);

    3)    добавление функции чтения очередей событий (их параметров).

    Эта схема реализует рекомендованную ARQU обработку параметров событий в main.  Кроме того, в такой схеме решается тяжелая задача подключения новых версий Lua в QUIK, так как не будет требоваться переработка в Qlua нативного управления автоматической ее памятью с целью реализации потокобезопасной уборки мусора, требуемой в старой схеме (из-за запуска функций коллбеков в потоке, отличном от потока main, но в контексте пользователя). Подключение новых версий Lua (в том числе и 5.3.5) станет в описанной выше схеме рутинной задачей.

При этом проблема сбоев автоматической памяти QLua 5.3, о которой я писал не раз в ветке «Грядущие изменения на срочном рынке МБ: поддержка работы с 19-значными номерами заявок и сделок» должна исчезнуть.
 
Можно в качестве предложения внести одновременную поддержку lua5.1 + jit и lua5.3 + ravi
https://luajit.org/
https://github.com/dibyendumajumdar/ravi
 
Свежие мечтатели к нам подключились, похоже :)) Которые еще не знают истории про "пожелание зарегистрировано".

Цитата
Александр написал:
lua5.1 + jit

Многопоточности в jit нет, в этом беда. А модель API для qlua сделали в QUIK многопоточной по самой идее, так что jit, похоже, нам с вами не светит никогда. Грусть.
 
Цитата
swerg написал:
Свежие мечтатели к нам подключились, похоже :))
    Это я к себя не отношу, но использую, как повод высказаться дополнительно.
У ARQU, существует три варианта, после перехода на Lua 5.3, порождающем множество проблем и не предоставляющем, по большому счету ни чего нового:
  1) отказаться от перехода на Lua 5.3 и у них для этого было железное алиби (Lua является фактически двухуровневым языком и все, что не реализуемо в собственно Lua 5.1, можно реализовать в C/C++, с которым Lua тесно интегрирован): причем,. фактором усиливающим озвученное алиби, могло быть соображение, состоящее в том, что они заботятся о стабильности среды разработки, предоставленной пользователям;
  2) "пробиться" через возникшие проблемы перехода на Lua 5.3, одной из которых является необходимость реализации, при сохранении существующей архитектуры обработки событий QUIK, многопоточности QLua 5.3 (по  сравнению с однопоточностью нативного Lua 5.3);
  3) изменить схему  обработки событий QUIK так, чтобы уйти от проблем многопоточности QLua.
 На первый вариант они не пошли (и, по-моему, зря), а теперь и не могут пойти (ведь кому-то, и не рядовым, за это пришлось бы отвечать).
 Со вторым вариантом, похоже, возникли проблемы, которые наблюдают многие пользователи.
 Третий вариант, описанный мною в этой ветке, действительно, качественно меняет архитектуру QUIK, при которой:
    1) исчезает требование многопоточности QLua (большой геморрой при переходе на новые версии Lua, в том числе на 5.3.5);
    2) обеспечивается независимость основного потока регистрация событий от пользовательского "произвола", возникающем при использовании коллбеков, в которых "непросвященный" пользователь может делать все, что угодно.
 Этот вариант был бы  достойным выходом для ARQU из сложившийся ситуации.
 
TGB, В третьем варианте все будет выполняться в одном потоке и привет переписывание скриптов.
 
Исполнение скриптов на разных версиях квика потребует разных алгоритмов.
 
TGB, Идеологически всё правильно: поток main - это поток юзера, второй поток - поток Квика, и, следовательно, они должны обмениваться данными именно механизмом обработки событий, а юзера "своими грязными лапами" в основной поток пускать нельзя. А sleep и есть "служебная функция ожидания", но ни в коем случае не "либо появления данных в очередях событий" - события есть аналог прерываний, и sleep есть аналог прерываний по таймеру, которые не должны перекрываться другими событиями. Хотя, конечно, вместо этого цикла с анализом флага isRun (это тоже флаг Квика, а не юзера!) разумнее иметь что-то типа Wait(), выход из которой осуществлялся бы по OnStop (и эта функция не юзеровская идеологически - его дело давить на кнопки "Остановка скрипта", а не обрабатывать своё же событие), а управление юзер получал бы по OnTimer(Nms). То есть имеем две очереди событий, от скрипта к Квику и наоборот, обе обслуживаются Квиком, при этом события для юзера вызывают соответствующие функции их обработки (OnTrade, скажем), а события от юзера передаются функциями, и не SendEvent, а более "приземлёнными" - SetCell, SetOrder (а не жутко выглядящая sendTransaction), etc. Но ведь это совсем другой язык, другая технология, так что я согласен с фразами про "мечтателей".  :smile:  
 
Цитата
Александр написал:
В третьем варианте все будет выполняться в одном потоке и привет переписывание скриптов.
Вообще говоря, я сторонник первого варианта (щадящего пользователей), но он уже не реален.
Если разработчики что-то изменят в работе с коллбеками, то пользователям, скорее всего, все равно придется что-то править в своих скриптах. В третьем варианте, в отличие от второго, есть хоть какой-то смысл.
 
Вообще говоря морока с main() была в QUIK внедрена по глупости считаю.
В каком потоке обрабатывать колбеки - это отдельный разговор, непосредственно к main() не имеющий отношения.
Но с main() квиковцы внедрили такую логику: колбеки вызываются до тех пор, пока не произошел выход из main(). Как вышли (добровольно, замечу!) из main() - так вызов колбеков прекращается.

И вот на какой вопрос я при этом не нахожу ответа. Если бы не было main() - каким образом останавливать обработку колбеков, когда автор скрипта уже не хочет чтобы колбеки вызывались? ну вот в самом деле, нельзя же все время для всех скриптов вызывать колбеки. Или можно?
Как этот момент решается на других платформах, кто-будь может рассказать? я вот сколько на метатрейдер смотрел - так и не смог найти ответ на вопрос: когда же "колбеки" из скриптов в нём перестают вызываться?
 
Цитата
swerg написал:
каким образом останавливать обработку колбеков, когда автор скрипта уже не хочет чтобы колбеки вызывались?
Очевидно, способом OnSometh ing = nil. Квик все равно колбек под pcall дергает, ну получит попытку вызова нила, снимет флаг "есть такой колбек" и поедет дальше как ни в чем не бывало.

Хотя я б наоборот один мейн и оставил (и убрал синхронизацию из луа). Хочет мейн событиев - регистрирует колбек, который будет вызываться в его же контексте, а для этого на входе должна быть очередь и мейн должен периодически дергать что-нибудь типа ProcessEvents. Вариант "с прерываниями", как Владимир выше написал, то есть если колбеки в потоке мейна выполняются асинхронно с ним самим, это путь в адъ, это как сигналы в сях, способ быстро убиццо апстену. Винда вон даже APC асинхронно не обрабатывает, хотя могла бы (контрольный вопрос: почему?).

Тксть тоже принял участие в народных мечтаниях в меру сил.
 
Anton, Почему "путь в адъ"? Путь в рай!  :smile:

Хочет мейн событиев - регистрирует колбек, который будет вызываться из второго потока, а обрабатываться "в его же контексте", а для этого на входе должна быть только регистрация обработчика, и никто никого не должен "периодически дергать". В УПОР не вижу здесь "способа быстро убиццо апстену".  
 
Цитата
swerg написал:
И вот на какой вопрос я при этом не нахожу ответа. Если бы не было main() - каким образом останавливать обработку колбеков, когда автор скрипта уже не хочет чтобы колбеки вызывались? ну вот в самом деле, нельзя же все время для всех скриптов вызывать колбеки. Или можно?
   Попробую ответить кратко, как, это, похоже, происходит сейчас в QUIKе.
 Основной поток запуска и обслуживания пользовательских скриптов (в том числе и его коллбеков) при запуске любого скрипта сканирует его в поисках его же коллбеков (по именам событий). По каждому скрипту ведется список найденных его меток (функций) колбеков в рамках его lua_State. При возникновении любого события, основной поток обходит последовательно lua_State всех запущенных скриптов и запускает (если находит) соответствующие коллбеки. При останове любого скрипта порождается событие <OnStop>, которое отрабатывает также основной поток. При этом список коллбеков остановленного скрипта обнуляется.
 
Цитата
Владимир написал:
В УПОР не вижу здесь "способа быстро убиццо апстену".  
Никто не знает, что колбек сделает, поэтому все состояние становится volatile. Если при вызове из другого потока спасают локи, то при вызове из себя же не спасет ничто.
 
Anton, Как это "никто не знает"?! Это же ИНТЕРПРЕТАТОР! Он же САМ исполняет функции юзера, в том числе, и код колбеков! Всё должно быть под полным контролем! Интерпретация - самый крутой тип исполнения программы в плане надёжности.
 
Цитата
TGB написал:
при запуске любого скрипта сканирует его в поисках его же коллбеков
Не сканирует, луа уже выполнил тело скрипта и колбеки уже есть в глобальном пространстве, достаточно проверить например is_function('OnAllTrade'). В остальном разве что про OnStop можно в деталях поспорить, да незачем, модель тоже достаточно релевантная, если в дебри не лезть.
 
Цитата
Владимир написал:
Это же ИНТЕРПРЕТАТОР!
...а не логический анализатор, именно. Он тупо буковку за буковкой выполняет и леса за деревьями не видит.
 
Anton, А ЧТО ИМЕННО он может "не увидеть"? Если юзер ковыряется в своей песочнице - ему и не надо ничего видеть, пусть ковырется на здоровье. А если вдруг собрался выполнить что-то "недозволенное" - схватит его за руку.
 
Цитата
Владимир написал:
Если юзер ковыряется в своей песочнице
1) как он это определит? К каждой переменной ярлычок привесит, чья она, и будет при доступе проверять?
2) речь вообще не про это. А про что - про это? А вот про что
Код
t = { }

function OnAllTrade(v)
  table.insert(t, v)
  table.sort(t)
end

function main()
  while true do
    table.sort(t)
    sleep(100)
  end
end
Оно и сейчас даст кашу, но сейчас хоть потоки разные и можно хоть бы и колхозную синхронизацию налепить. А если они обе в мейне будут асинхронно выполняться, не будет даже теоретической возможности что-то там синхронизировать. Ну то есть будет путем реализации потоков в потоках (как бы их ни назвали), то есть очередного героического изобретения лисапедов.

Резюме: внутри потока смена контекста только кооперативная, сиречь синхронная. Никаких чудесных изобретений тут быть не может.
 
Anton, А что тут определять? Переменные - это ЕГО переменные, пусть делает с ними, что хочет. Критический момент тут может быть разве в том случае, если пришло ещё одно прерывание, а он не успел обработать это, но такая ситуация ловится тривиально.

2) А с какого бодуна "они обе в мейне будут асинхронно выполняться"? При такой технологии код мейна должен быть примерно такой:
Код
function main()
 SetInterrupt(OnTime, 1000, "MyHandler");
 Wait();
end

function MyHandler(v)
  table.insert(t, v)
  table.sort(t)
end
То есть main производит какие-то телодвижения при запуске скрипта, настраивает обработчики и ОТДАЁТ управление, которое передастся в этот поток уже по прерываниям, конкретному обработчику, вроде MyHandler:

А по нажатию кнопки останова ВЕРНЁТ управление мейну (вылетит из  Wait и пойдёт выполнять что там дальше написано). Чего, кстати, как Вы подсказали, она сейчас как раз и не делает (точнее, делает, но не всегда).
Цитата
Резюме: внутри потока смена контекста только кооперативная, сиречь синхронная. Никаких чудесных изобретений тут быть не может.
А вот это спорный вопрос!  :smile:  Вот фрагмент из моей книги:

На наш взгляд, принятая в среде Windows двухшаговая модель обработки сообщений идеологически непригодна для программирования в событиях. Мало того, что этот сервис относится (в терминологии SINT) к аппаратному уровню и, следовательно, обеспечивает переносимость кода разве что с Windows95 на WindowsXP. Куда более серьёзным возражением является то, что при таком подходе программирование в событиях представляет собой всего лишь замаскированное операторное программирование. Действительно, первичный обработчик каждой очереди сообщений Windows раздаёт их адресатам, у каждого из которых имеется собственный (вторичный) обработчик. Такой подход имеет сразу несколько весьма неприятных следствий. Во-первых, при отправке сообщения необходимо заранее знать адрес (дескриптор) получателя, хотя на момент отправления события адресат может вообще не существовать. Во-вторых, обезличенность событий позволяет программам иметь единственный обработчик «на все случаи жизни», а всю информацию, специфицирующую объекты реакции на события, вынести в виртуальные обработчики, т.е. в данные, которые могут находиться как внутри тела программы, так и вне его. Кроме того, большинство меню пользователя имеют один и тот же обработчик даже на уровне данных (управление курсором, клавиши Enter, Esc). Программистом такой «обработчик по умолчанию» вообще не указывается – это дело конструктора соответствующего меню. Специализированные обработчики обычно перехватывают нескольких специальных событий, а обработку остальных наследуют от более универсальных.

Ещё более неприятное следствие подхода Windows состоит в том, что приходится прилагать значительные усилия, чтобы позволить программам свободно обмениваться сообщениями друг с другом или внешними устройствами, и в то же время максимально изолировать приложения, чтобы крах одного из них не вызвал крах других или всей системы. Это синхронизация очередей сообщений, контроль их доставки, перемещений внутри потоков, обработка аварийных ситуаций. Например, что делать с сообщениями, если окно-адресат закрывается? Ответ нелегко дать даже в философском плане. У Windows очередь таких сообщений просто сбрасывается. В технологии SINT диспетчер посылает текущее событие всегда текущему активному обработчику. Это позволяет направлять группу событий сразу многим обработчикам, при этом часть событий может быть предназначена для переключения обработчиков, осуществляя своего рода навигацию по ним. Под управляющим воздействием этой группы обработчики могут рождаться, обрабатывать предназначенные им события и умирать, передав остаток необработанных событий очередному обработчику.

У нас пока не возникало необходимости программирования многозадачных приложений, хотя техническая возможность создания нескольких процессов в рамках одного приложения имеется, и даже не очень сложна в реализации. Следует лишь помнить, что методы класса "функции" работают на одном и том же программном стеке, и при переключении процессов следует заботиться о сохранении и восстановлении данных этого стека. Внутри же одного процесса обработка событий в SINT также имеет радикальные отличия от той же Windows, касающиеся приоритетов. В обоих случаях обработка обычно происходит в порядке поступления (очередь). Что же касается асинхронных (срочных) событий, мы полностью отказались от управления последовательностью их обработки с помощью приоритетов: любое событие, даже имеющее наивысший приоритет, всегда можно при необходимости обогнать. Это принципиально невозможно для Windows, где обработчик срочных сообщений вызывается напрямую, и до окончания его обработки никакое другое сообщение не может быть обработано. Таким образом, объект реакции на событие не может иметь класс "группа событий", что создает колоссальные трудности при программировании диалога (в SINT более половины всех объектов диалога принадлежат именно этому классу).
 
Цитата
Владимир написал:
код мейна должен быть примерно такой
По сути в примере мейна просто нет. Это тот самый метатрейдер, о котором выше swerg писал. Этот wait на практике будет реализован как
Код
void Wait()
{
    while(GetMessage(&msg))
    {
      if(HandlerRegistered(msg.type))
        InvokeHandler(&msg);
    }
}
Цикл сообщений спрятан от юзера и больше никакой разницы с моим вариантом. А прятать, ящитаю, плохо. Событие "нет событий" тоже событие.

Цитата
Владимир написал:
хотя на момент отправления события адресат может вообще не существовать
Это жесть конечно.

Чесгря, про винду там неправды понаписали. Вот я тут автологин выкладывал, там очередь сообщений есть, а окна нет.
 
Anton, Э, нет! Этот wait на практике будет реализован как передача управления основному потоку, и выполняться он будет именно там (при нажатии кнопки "Стоп" (OnStop вообще недоступен юзеру) вернёт управление в main, к следующему за Wait оператору - разница принципиальная!

Событие "нет событий" тоже событие? Нет, за всё время моих занятий программированием я с таким толкованием ещё не встречался.  :smile:
Цитата
Это жесть конечно.
Прям уж! Тривиальнейшее, постоянно встречающаяся ситуация.
Цитата
Чесгря, про винду там неправды понаписали.
Ну... писал я это довольно давно, и на тот момент это, по-моему, было правдой. :smile: Что до "окна" - имелось в виду не видимый на экране прямоугольник, а... впрочем, вот цитата оттуда же, чуть раньше:

С лёгкой руки Билла Гейтса, объект обработки сообщений, как правило, называют окно. Поскольку ОС Windows является одной из самых популярных систем, в которой реализована, хорошо отлажена и документирована технология работы с сообщениями, мы будем сравнивать наш подход именно с ней. При изложении концепций SINT мы будем использовать близкие по смыслу термины меню и событие соответственно.

 
добавлю свои пять копеек.
---------------------------
сделал бы для каждого вида колбека отдельный пул потоков.
 
либо проще
обслуживание колбеков пулом потоков без разделение на виды.
 
Цитата
Владимир написал:
за всё время моих занятий программированием я с таким толкованием ещё не встречался
Встречались-встречались, вот прям в этом самом квике (арка не смотрит?)
Код
while(true)
{
    if(PeekMessage(&msg, ...))
        ProcessMessage(&msg);
    else if(HaveNetworkEvents())
        ProcessNetworkEvents();
    else
        WaitMessage();
}
И 99% игрушек построено аналогично, только там WaitMessage вообще нет, они графику свою отрисовывают беспрестанно. Так и получается, сообщений нет, а деятельность бурная есть.

Цитата
Владимир написал:
Этот wait на практике будет реализован как передача управления основному потоку
Вы хотите солнце вручную закатывать. Тот поток и так отдельный, он прямо сейчас, может быть, на другом ядре выполняется вовсю. Нашему потоку надо просто встать и подождать сообщений, остальное разрулит винда. GetMessage, если сообщений нет, вызовет внутри тот же WaitMessage, а он встанет на WaitFor* до получения сообщений. Поток не будет вхолостую молотить цикл до победного, как можно подумать на первый взгляд, GetMessage блокируется. Явная передача конкретному потоку в винде вообще невозможна, мы можем только отказаться от своего процессорного времени, а кому его винда отдаст - неуправляемо.

Цитата
Владимир написал:
имелось в виду не видимый на экране прямоугольник
Ну это-то понятно. Винду надо было назвать Objects и сделать низшей единицей именно объект, не привязанный к экрану, а окно от него унаследовать. Они потом это осознали и сделали "окна только для сообщений", без всего экранного оверхеда. Но как костыль уже.
 
Цитата
TGB написал:При останове любого скрипта порождается событие <OnStop>, которое
Об этом и мой вопрос: как скрипту себя остановить? как сказать "я устал, я ухожу, не дергайте больше мои колбеки" без наличия main() ?
 
Anton, Не, Я - не встречался! И игрушка моя, кажись, единственная (шахматы), и вообще любая прога с событиями (т.е. 99% всех моих программ) отсутствие событий никаким событием не считают. А на события только отвлекаются, прерывая свою "деятельность бурную".  :smile:

Что значит "солнце вручную закатывать"?! Интерпретатор нарывается на Wait, ставит В СВОЙ OnStop операцию возврата управления, И ЗАБЫЛ НАФИГ ПРО ЭТОТ СКРИПТ ВААПЩЕ! Только по прерываниям передаёт управление зарегистрированным там обработчикам (естественно, никакого "сканирования" для этого не требуется). Какая разница, на каком там ядре что выполняется? Нашего потока в этом случае тупо НЕТ! И до Винды, кстати, тоже никакого дела нет.
Цитата
Винду надо было назвать Objects
Ну да, ну да - теперь пойдёт у нас уж музыка не та, у нас запляшут лес и горы!(С)  :smile:

Нет, лично я убеждён, что делать низшей единицей надо именно ПУСТОЙ объект! РЕАЛЬНО пустой, а не тот, который "умеет прорисовывать себя на экране, реагировать на события" и ещё какую-то хрень делать, не помню уже. От такого объекта тупо НЕЧЕГО наследовать.

swerg,
Цитата
Об этом и мой вопрос: как скрипту себя остановить? как сказать "я устал, я ухожу, не дергайте больше мои колбеки" без наличия main()?
Так сказали же, вроде: по OnStop сбросить все заказанные обработчики и отдать управление в main.
 
Цитата
Владимир написал:
Интерпретатор нарывается на Wait, ставит В СВОЙ OnStop операцию возврата управления, И ЗАБЫЛ НАФИГ ПРО ЭТОТ СКРИПТ ВААПЩЕ! Только по прерываниям передаёт управление зарегистрированным там обработчикам (естественно, никакого "сканирования" для этого не требуется).
Предполагается, что интерпретатор работает в неком контексте и по неким "прерываниям" переключает контекст на зарегистрированный обработчик, дает ему доработать до победного и переключает контекст обратно. Это и есть кооперативная многозадачность, о которой говорили большевики. А юзер решил порешать задачу коммивояжера в обработчике. И все, вся система встала колом. Теперь интерптетатору надо прибивать этот скрипт, потому что асинхронно снять его контекст на полпути и потом снова в него войти он уже не может. То есть он может снять, что-то повыполнять другое и переключить контекст снова на этот скрипт, только для скрипта уже произошли неожиданные изменения в окружении (состояние стало volatile), на что он не рассчитывал, так что результаты его продолжения будут мусорными, а значит и продолжать его смысла уже нет, в морг значит в морг.

Цитата
Владимир написал:
Нашего потока в этом случае тупо НЕТ!
Давайте чуть модифицируем пример выше:
Код
function main()
 int magic = 123;
 SetInterrupt(OnTime, 1000, "MyHandler");
 Wait();
 print("%d\n", magic);
end

function MyHandler(v)
  table.insert(t, v)
  table.sort(t)
end
Мейн создал переменную, зарегистрировал обработчик и ушел ждать событий (как он думал), но на самом деле просто умер ("потока тупо нет"). После возврата из Wait поток реинкарнировался и хочет показать миру свою переменную. Это допустимый сценарий? Тогда вопрос - где в это время хранилась эта переменная? Отвечаю: она хранилась в контексте потока, который, оказывается, был таки жив, только снят с выполнения. Так выходит, разницы с этим wait и тем, что я выше показал, нет никакой, оба спят, только в моем переключением контекстов занимается винда (или другая ось), а в самопальном надо делать свой шедулер, свои стеки, свои потоки, свою  синхронизацию, свое вообще все.

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

Цитата
Владимир написал:
делать низшей единицей надо именно ПУСТОЙ объект!
Ну так о том и сказано было. Однако, чтобы быть сколько-нибудь полезным, этот пустой объект должен уметь: а) рождаться (конструктор); б) умирать (деструктор); в) опционально клонироваться (копирование/присвоение). Остальное добавится наследниками. И вуаля, в одной ветке мы изобрели исключения, в другой - классы и наследование. Все, что нам осталось, это синхронизировать терминологию с существующими решениями и подивиться, что вон же ж оно уже все было оказывается, только называлось по-другому.
 
Цитата
swerg,  
Цитата
Об этом и мой вопрос: как скрипту себя остановить? как сказать "я устал, я ухожу, не дергайте больше мои колбеки" без наличия main()?
Так сказали же, вроде: по OnStop сбросить все заказанные обработчики и отдать управление в main.

Внимательнее вопрос стоит прочитать.
Модель другая: нет main() чтобы не было многопоточности, есть только обработчики.
OnStop - это если пользователь остановить захотел.
А если скрипт сам захотел остановиться - откуда OnStop возьмётся?!
Вопрос был: как в модели без main() скрипту самого себя остановить? как это сделано в других имеющихся системах торг. терминалов (не фантазийных), кто знает?
 
Anton, Правильно предполагается! Интерпретатор и "работает в неком контексте и по неким "прерываниям" переключает контекст на зарегистрированный обработчик, дает ему доработать до победного и переключает контекст обратно". Это никакая не "многозадачность" - работает ТОЛЬКО интерпретатор, а сами скрипты есть просто пассивные куски кода, голый текст, который сам делать ничего не умеет.

ЕСЛИ "юзер решил порешать задачу коммивояжера в обработчике" и ИЗ-ЗА ЭТОГО "вся система встала колом", ТО гнать надо поганой метлой разработчиков такого "интерпретатора"! Не надо никого "прибивать" - в некоторых моих задачах (генератор сайтов или обработка баз данных) часть аналогичных скриптов вообще А ФАЙЛАХ лежат, и "асинхронно снять его контекст на полпути и потом снова в него войти" как два пальца об асфальт! Да чего далеко ходить - в этом самом моём скрипте на Lua часть кода находится именно во внешних файлах, и исполняется, как будто он набит в теле программы (loadstring) - и прекрасно работает! И никаких "неожиданных изменений в окружении" не происходит".

Разумеется, этот пример допустимый! И скрипт должен напечатать "123". Мейн в этой технологии ТОЧНО ТАКОЙ ЖЕ обработчик прерываний! Включается по запуску, выключается по Wait и снова получает управление по останову. Грубо говоря, утром включили, вечером выключили, а всё это время его НЕТ. Где хранилась переменная? В контексте скрипта. Ведь обработчики тоже пользуются не только своими локальными переменными! И при чём тут ваще "ось"? Какие могут быть "потоки" у интерпретатора? Точнее, у интерпретатора-то они теоретически могут быть (хотя и ему они, по большому счёту, нафиг не нужны), но у интерпретируемых им сраных текстов... Какой "шедулер", какие "свои стеки", какая "синхронизация" - побойтесь Бога!

Вот именно, что НЕ ДОЛЖЕН "тот пустой объект "уметь: а) рождаться (конструктор); б) умирать (деструктор); в) опционально клонироваться"! НЕ ДОЛЖЕН! Пустой объект - значит ПУСТОЙ! Какой Вы предлагаете "конструктор" для объектов класса "функция"? Вот именно: НИКАКОЙ! А что собрались оттуда "наследовать"? Вот именно: НИЧЕГО! А исключениям и вообще место только на помойке!

swerg, Внимательнее ответ стоит прочитать.  :smile: main - это ТОЖЕ обработчик, и никакого отношения к многопоточности не имеет.

OnStop - это при нормальной организации НЕ ЮЗЕРОВСКАЯ функция, а системная. Так что нужно просто послать сообщение "убей меня". А можно и не посылать: main закончился - интерпретатор знает, что нужно делать. По крайней мере, ДОЛЖЕН знать!

НЕ БЫВАЕТ "модели без main()"! При запуске скрипта ЧТО-ТО должно начать выполняться. Вот это "что-то" и есть main, хоть горшком её назови.
 
Цитата
Владимир написал:
Правильно предполагается!
Ну вот, теперь можно к конкретике. Таки юзер решил порешать задачу, которая будет решаться до 2089 года. Интерпретатор, допустим, через 30 секунд решил, что чот не то, его действия?

Цитата
Владимир написал:
Это никакая не "многозадачность" - работает ТОЛЬКО интерпретатор
Дык и на процессоре тогда никакая не многозадачность, работает только ядро, а выполняемые им опкоды это всего лишь пассивные байты, которые сами ничего не умеют.

Цитата
Владимир написал:
Какой Вы предлагаете "конструктор" для объектов класса "функция"?
Ну вот в луа например любимый loadfile как раз и есть конструктор объекта функция, он парсит глупый текст и превращает его в байткод. Если документацию на него почитать, там так и написано: If there are no syntactic errors, returns the compiled chunk as a function.
 
Anton, Да никаких действий! Пусть себе решает! Интерпретатор же просто квантует время и периодически что-то там ему выполняет "в свободное от работы время". Ну, может сказать: "Эй, чувак! Твой обработчик уже полчаса молотит! У тебя ничего не случилось"?

Именно! И на процессоре никакая не многозадачность! Вот если более одного ядра, тогда да, а так для IP эти "опкоды" именно "всего лишь пассивные байты, которые сами ничего не умеют" - это для него ДАННЫЕ! Это очередь данных. А вместе с SP это стек очередей тех самых пассивных данных". А потому, огранизовав аналогичный стек на данных и запрограммировав интерпретацию команд некоего подмножества ассемблера, мы получаем возможность почти полноценного программирования данными, которые могут располагаться даже во внешних файлах (в частности, в теле БД).

Ничего подобного! В луа loadfile НЕ ЕСТЬ "конструктор объекта функция"! Да, в интерпретаторе (теоретически) можно даже динамически склепать тело функции в переменной (это же просто строка!) и вызвать потом эту переменную как функцию, но в реальной жизни интерпретатор почему-то обычно боится это делать - как и в случае с goto имеем кастрирование возможностей программиста.
 
Цитата
Владимир написал:
Интерпретатор же просто квантует время и периодически что-то там ему выполняет "в свободное от работы время".
Мы ж договорились, что интерпретатор загружает контекст обработчика и отдает ему всю вычислительную мощность до победного завершения, как принято в кооперативной модели. А уже раз и квантует время, а это уже модель вытесняющая. Концепция поменялась?

Цитата
Владимир написал:
А потому, огранизовав аналогичный стек на данных и запрограммировав интерпретацию команд некоего подмножества ассемблера,
мы получаем эмулятор некого процессора, существующего или гипотетического. Так же, как луа симулирует некую выдуманную стековую машину. Так же, как ява. Так же, как сишарп. Или как qemu симулирует существующие процессоры. Или как virtualbox симулирует ажно целый компьютер со всей периферией. И опять подкрадывается тот же вопрос - а главное зачем.
 
Anton,
Цитата
Мы ж договорились, что интерпретатор загружает контекст обработчика и отдает ему всю вычислительную мощность до победного завершения, как принято в кооперативной модели.
ВСЮ?! Нет, я-то уж точно об этом не договаривался!  :smile: Не знаю, что там за "кооперативная модель", но у интерпретатора (точнее, при любом программировании данными) может быть ТОЛЬКО модель вытесняющая, иначе это не интерпретатор, а говно. Концепция не менялась, она вообще родом из прошлого тысячелетия!

Да, "мы получаем эмулятор некого процессора", и этот процессор РАБОТАЕТ! Я же сказал, "зачем" - для возможности программирования данными! Любой интерпретируемый язык - это именно программирование данными в девственно чистом виде.
 
Владимир, Вот ещё парочка фрагментов из моей книги:

При старте программы пакетной обработки открываются файлы входных потоков данных (в т.ч. при необходимости файлы управляющих потоков) и создаются файлы выходных потоков. Вся необходимая информация для этого содержится в стартовой очереди методов, а также, возможно, в аргументах командной строки и/или файлах шаблонов, управляющих процессом обработки. В некоторых случаях эти потоки могут многократно переоткрываться – например, генератор сайтов за один цикл может создать сотни и тысячи веб-страниц, используя сотни и тысячи файлов шаблонов и других входных данных.

В своё время начальник буквально заставил нас написать «инструкцию пользователя» (у нас на неё никогда не хватало времени), фрагменты которой я и предлагаю вашему вниманию.
2. При генерации выходного файла могут быть открыты одновременно до трёх управляющих файлов разных типов:
• текущий конфигурационный файл;
• файл текущего шаблона;
• текущий входной файл данных.
3. Любой из управляющих файлов может содержать вложенные файлы, подключаемые командой #include FileName[#LabelName]. После обработки вложенного файла (или по команде #return) генератор возвращается к обработке родительского файла. Команда #jump FileName[#LabelName] осуществляет передачу управления между файлами одного типа, при этом возврат к обработке родительского файла не происходит. Переход внутри текущего файла выполняется по команде #goto LabelName.
7. Информация в конфигурационном файле предназначена для управления последовательностью генерации выходных файлов и определения глобальных переменных. Текущий выходной файл генерится на основании информации, содержащейся в файле текущего шаблона и текущем входном файле данных. Переключение входного потока данных между ними (режим сопрограмм) осуществляется при появлении во входном потоке символа-разделителя частей, определяемого командой EndOfPartSymbol. Генерация выходного файла заканчивается по окончанию первого файла шаблона, открытого при начале генерации (или файла, на который он был переключен директивой #jump). После окончания генерации выходного файла программа переходит к обработке очередной команды файла конфигурации. Работа программы завершается по окончанию файла конфигурации, открытого при старте программы (или файла, на который он был переключен директивой #jump).
II. Объявление и использование переменных
1. Переменные, как и команды, могут описываться в любом из трёх управляющих файлов. Область действия переменных по умолчанию устанавливается от момента её объявления до конца обработки файла, в котором она была определена.
2. Переопределение переменной (директива #replace), объявленной во внешнем файле по отношению к данному, автоматически упрятывает старое значение переменной и восстанавливает его по окончанию обработки файла, в котором она была переопределена (или по команде #pop VarName). Переопределение переменной, объявленной в том же файле, уничтожает её предыдущее значение, поэтому, в случае необходимости его сохранения, нужно воспользоваться командой #push VarName.
3. Любая переменная может содержать вложенные переменные, имена которых задаются непосредственно в теле родительской переменной и отмечаются с двух сторон символами-ограничителями VarSymbol.
5. Системные команды и переменные начинаются с символа «_». Переопределять системные команды и переменные не рекомендуется.
6. Значение переменной, если оно начинается с ограничителя, должно также оканчиваться ограничителем, что дает возможность описывать многострочные переменные. В противном случае, конец тела переменной определяется по символу конца строки или началу комментария. Разделитель частей файла может встречаться в теле переменной.
III. Массивы, указатели, функции, циклы
1. Массив однородных переменных объявляется по директиве #array. Элементы массива (значения переменных и/или их имена) задаются внутри ограничителей массива (скобки {} или #begin, #end) и отделяются друг от друга разделителями переменных (по умолчанию запятыми). Чтобы отличать имена переменных от их значений, имена должны ограничиваться с двух сторон символами-ограничителями переменных, задаваемых командой VarSymbol.
2. Указатель на массив (переменную) задается командой #pointer. С указателем могут выполняться арифметические операции, которые переводят указатель к заданному элементу (индексу) массива. Индексы нумеруются с нуля.
3. Описание функции задается командой #func  (FuncName ([Arguments]), вызов функции – командой #run FuncName ([Arguments]). Контроль количества и типов аргументов функции не производится. Ошибки такого рода выявляются на стадии исполнения и приводят к аварийному завершению работы генератора (InvalidData).
4. Программирование циклических операций выполняется по команде #for, при этом непосредственно после директивы #for описываются действия, выполняемые до цикла, после директивы #until – условие прекращения цикла (аналогичное по смыслу команде #if), после директивы #do идёт само тело цикла до команды #next. Допускаются вложенные циклы.


Или даже:
Примеры команд:
#if ((Тип == DOCUMENT) && ((Дата == NULL) || (Автор == NULL))) #then #inc.var (Total_Sum) – посчитать количество узлов типа DOCUMENT, у которых не указан либо автор, либо дата создания. Результат подсчёта сложить со значением ячейки Total_Sum, ранее определенной в шаблоне командой #var (но реально созданной в теле SINT-программы).
#run FuncName ([Arguments]) – вызов функции.
#include my_template – вызов вложенного шаблона по имени файла.
#call my_template#my_func – вызов функции, расположенной в теле внешнего шаблона.
#call #my_func – вызов функции, расположенной в теле текущего шаблона.
Последние три примера (отметим, что команды #call и #include являются синонимами) представляют собой аналог вызова процедуры в обычных языках программирования. Адрес возврата запоминается в стеке очередей, затем открывается (при необходимости) новый шаблон и (если указано имя вызываемой процедуры) файловый курсор переводится на начало этой процедуры. Определение адреса процедуры заключается в поиске её имени, которое представляет собой метку, заданную командой #label. Возврат из процедуры осуществляется по команде #return (или по достижению конца файла шаблона). По команде #goto или #jump выполняется такой же переход по метке, но не затрагивающий стек очередей.
 
Цитата
Владимир написал:
у интерпретатора (точнее, при любом программировании данными) может быть ТОЛЬКО модель вытесняющая
Цитата
Владимир написал:
Какой "шедулер", какие "свои стеки", какая "синхронизация"
Цитата
Владимир написал:
Какие могут быть "потоки" у интерпретатора?
Какая может быть вытесняющая модель без потоков, шедулера (планировщика потоков), синхронизации?

Цитата
Владимир написал:
отметим, что команды #call и #include являются синонимами
Думаю, тут добавить уже и нечего. Вы придумали msbuild, может и раньше апача и потырившего идею майкрософта, а может и не раньше.
 
Anton,
Цитата
Какая может быть вытесняющая модель без потоков, шедулера (планировщика потоков), синхронизации?
Обыкновенная. Все скрипты есть просто куски текста, так что никаких потоков там нет и быть не может. Дойдут руки у интерпретатора - выполнит команду, нет - так и будут лежать голым текстом.

Да ничего я не придумывал"! Синонимы команд - обычный сервис: кому-то удобнее begin-end, кому-то {} - почему бы не дать такую возможность? А уж в именах объектов и их атрибутов синонимов и вообще может быть выше крыши (я имею в виду базы данных).
 
Цитата
Владимир написал:
Anton,  
Цитата
Какая может быть вытесняющая модель без потоков, шедулера (планировщика потоков), синхронизации?
Обыкновенная. Все скрипты есть просто куски текста, так что никаких потоков там нет и быть не может. Дойдут руки у интерпретатора - выполнит команду, нет - так и будут лежать голым текстом.

Да ничего я не придумывал"! Синонимы команд - обычный сервис: кому-то удобнее begin-end, кому-то {} - почему бы не дать такую возможность? А уж в именах объектов и их атрибутов синонимов и вообще может быть выше крыши (я имею в виду базы данных).
Не знаю, что за книгу вы написали и здесь пиарите, но в языках и виртуальных машинах вы ноль без палочки
------------------
Где Вы увидели интерпретатор в реализации луа в квике?
Это VM а не интерпретатор
и там не куски текста а байт код - т е это машинный язык именно VMLua.
------------------------
Пардон, что то я сильно бисер разметал...
 
nikolz, О, Господи! Говорил уже, что "знатоков развелось - прям плюнуть негде". :smile:

Открываем книжицу "Руководство пользователя" от ARQA - так там буквально в названии чёрным по белому: "ИНТЕРПРЕТАТОР языка Lua".

VM, да будет Вам известно, это ТОЖЕ интерпретатор! Только на другом языке интерпретируемые данные записаны.
 
Книга видимо неизданная.
На рубеже веков при появлении CRM было модно создавать свои интерпретируемые языки программирования и я тоже написал такой, на котором пару лет писались конфигурации, пока 1С всех не победил. Подтверждаю, что переход от разбора текстовых лексем каждый раз к созданию байт-кода после первого прохода на несколько порядков увеличивает производительность.

Наверное бывшие коллеги "соавтора бортовых систем" до сих пор празднуют избавление от одного парня с цепким умом, но дремуче малограмотного и с большим самомнением...))
 
Artem, Господи, что вам всем так неймётся?..

Не знаю, "мода" эта как-то мимо нас прошла. Что за мода, бейсики писать? Ежу понятно, что язык, предназначенный именно для компа, исполняется заметно быстрее, чем "человеческий". По моим оценкам, там только один порядок.

Если "грамотность" проявляется в перлах типа "Это VM а не интерпретатор", то я предпочитаю быть малограмотным.  :wink:  
 
Цитата
Владимир написал:
НЕ БЫВАЕТ "модели без main()"! При запуске скрипта ЧТО-ТО должно начать выполняться. Вот это "что-то" и есть main, хоть горшком её назови.

Чушь.
Берем скрипт и начинаем из него дергать колбеки по мере поступления событий.
Никакой main() для этого не нужен. И ничего "что-то" выполнять постоянно для этого тоже не требуется.
 
swerg, Чушь. Кто именно и с какого бодуна вдруг станет "брать скрипт" и, тем более, "начнёт него дергать колбеки по мере поступления событий". Как этот "кто-то" вообще узнает, что нужно делать? Как узнает, где там "колбеки"? По фиксированным именам? Кто вообще сказал, что скрипт запрашивает колбеки? Может, они ему нафиг не нужны. А что "ничего "что-то" выполнять постоянно не требуется", я и пытаюсь вдолбить чуть ли не всю эту ветку - не придурошный цикл с анализом флага останова, у примитивный wait.
 
Swerg,

не корми тролля.
www.bot4sale.ru

Пасхалочка для Алексея Иванникова: https://forum.quik.ru/messages/forum10/message63088/topic7052/#message63088
 
Ладно, хрен с ним с этим троллем.
Я на самом деле никак не могу получить ответ на свой вопрос, который давно меня заботит.
Ну вот как это сделано в метатрейдере, в других терминалах? нигде ж нет никакого main(). Есть по сути просто скрипт с колбеками (да? я не ошибаюсь?)
И вот когда в этих системах прекращается вызов этих колбеков?? я никак не могу этот момент найти, или ищу плохо.
Или там после запуска скрипта вызов из него колбеков никогда не прекращается?
Расскажите, а
 
swerg, Может, хватит, господа?  :wink: Сначала один нёс какую-то клиническую ахинею про "роботов и всякие прочие глупости", да ещё с гнутыми пальцами вроде "вы даже понимаете суть вопроса". Получил щелчок по носу - теперь чего-то шипит про "троллей". Потом второй начал пальцы гнуть на тему API в том же ключе: "По-моему вы ничего не понимаете", да про int-float ("Как бы по мягче сказать, что вы не разбираетесь в теме. Повторю в квике 7, lua 5.1 - в нем не числа хранятся типом double, соответственно нельзя хранить int64"), да про "не надо путать стек процессора и стек Lua - это разные стеки. Вам бы документацию почитать и хорошенько разобраться в луа", да про "выучи английский", да про "умение читать документацию и гуглить", после чего вообще забился в истерике. Потом третий понёс пургу про "монстров фондового рынка", и тоже с гнутыми пальцами: "Вы еще далеки от понимания реальности фондовых рынков" и совсем уж клинический бред с ещё большей распальцовкой: "вот некоторые из аксиом, которые надо усвоить и научится программировать", затем бред про мантиссы ("для справки: Разрядность мантиссы в 64 битном вещественном числе составляет 52 бита, что  позволяет точно отобразить лишь 16 разрядное десятичное целое число, а не  18 квинтиллионов, как наивно полагает Владимир"), затем про "это VM а не интерпретатор", и тоже с истерикой: " в языках и виртуальных машинах вы ноль без палочки"... я прям утомился этому неучу по носу щёлкать!  :smile: Потом Вы. Ваша квалификация несколько выше, но стиль тот же, вплоть до прямой лжи: "Как уже всем известно, документацию Владимир не читает". А причина-то в другом - просто я с раннего детства не перевариваю распальцованных дураков и редко спускаю им их "поучения".

А "вопрос, который давно Вас заботит", выеденного яйца не стоит, ибо main есть ВСЕГДА! Поймите же, наконец, простую вещь: ЛЮБОЙ интерпретатор ОБЯЗАН знать, когда и с какого места нужно начинать интерпретировать представленный код, когда и в каком месте нужно прекратить это делать. И лучший способ это сделать - создать утилиту с согласованным именем: тот самый main. Эта технология была разработана ещё в прошлом тысячелетии - тогда на планете Земля ещё водились программисты. И на Ваш вопрос: "А если скрипт сам захотел остановиться - откуда OnStop возьмётся?!" ответ уже давался: сбрасывайте этот дурацкий флаг isRun НЕ ТОЛЬКО в OnStop, а в любом другом месте, где он "захотел остановиться". Или воткните в этот дурацкий цикл НЕ ТОЛЬКО sleep, но и хоть сотню конструкций if blah-blah-blah then break;end;

P.S. На всякий случай только что проверил оба способа - всё прекрасно работает.
 
Цитата
swerg написал:
Ладно, хрен с ним с этим троллем.
Я на самом деле никак не могу получить ответ на свой вопрос, который давно меня заботит.
Ну вот как это сделано в метатрейдере, в других терминалах? нигде ж нет никакого main(). Есть по сути просто скрипт с колбеками (да? я не ошибаюсь?)
И вот когда в этих системах прекращается вызов этих колбеков?? я никак не могу этот момент найти, или ищу плохо.
Или там после запуска скрипта вызов из него колбеков никогда не прекращается?
Расскажите, а
В метатрейдере скрипт работает в отдельном потоке. В метатрейдере скрипт работает пока пользователь его не завершил или не возникла ошибка.
В квике скрипт выполняется в 2-х потоках: цикл, который вызывает колбеки и работает в основном потоке + пользовательский цикл, который работает в отдельном потоке, чтобы пользователь смог в нем реализовать какие-то необходимые действия. Если пользовательский цикл прекращает работу, то прекращается основной цикл. В итоге в квике пользователь может получить доступ к данным из 2-х потоков, что может вызывать лишние проблемы.
В общем все сводится к тому, что надо было изначально делать работу скрипта в одном потоке. В квике очень плохо спроектированное api, из-за которого возникает множество проблем и приходится создавать лишние "костыли". Поэтому я лучше буду использовать lua api и всю логику работы робота выносить в другой процесс.
 
Цитата
Александр написал:
В метатрейдере скрипт работает в отдельном потоке. В метатрейдере скрипт работает пока пользователь его не завершил или не возникла ошибка.

Спасибо, вы рассказали то, что я никак не мог найти в документации, да и просто в интернетах.

Цитата
Александр написал:
В квике скрипт выполняется

А как работает QLua - я знаю отлично :)
https://quik2dde.ru/viewtopic.php?id=16
Страницы: 1 2 След.
Читают тему
Наверх