Serge123 написал: хочется копать вглубь и искать там золотые самородки. До сих пор ничего роботоподобного не сделал...
Прежде чем копать, наверное, стоит выбрать место для копания. То есть, сначала поторговать вручную, чтобы понять что это такое, но без фанатизма, чтобы не слить весь ваш депозит. При этом надо понимать, что реально работающую стратегию, стабильно, без провалов, приносящую доход хотя бы в 20% (в текущий момент) на годовом периоде, вам никто не предложит. Подумайте, зачем банкам бегать за клиентами с предложениями кредитов под 15% если на фондовом рынке можно заработать 20%. Фондовый рынок, локально, это игра с "псевдо-нулевой" суммой (деньги на нем не создаются а перераспределяются) и если какая то стратегия оказывается выигрышной, а затем получает широкое распространение, то она перестает работать. После некоторого периода ручной торговли сделайте простого робота исключительно на QLua, который смог бы вас заменить, а также торговать на истории. И только после этого начните поиск своей стратегии и оптимизацию того, что имеет смысл оптимизировать.
2.
Цитата
Serge123 написал: На этом форуме могут до кровохарканья обсуждать двойные и тройные очереди, показывать загадочные картинки, от которых рябит в глазах, но ничего действительно полезного не скажут.
Не согласен (частично). Конечно, на форуме много флуда, но тот же Nikolay написал вам практически все об обработке обезличенных сделок.
Евгений написал: Подскажите выскочила ошибка: "attempt to index a nil value" на строчку: "if getFuturesLimit(FIRM, ACCOUNT, 0, "SUR").cbplplanned==nil then"Вроде как раз на nil проверяю.
У вас getFuturesLimit(FIRM, ACCOUNT, 0, "SUR") равно nil, а его индексировать нельзя.
Мне интересна реакции разработчика QUIK, в лице поддержки, на те пункты, которые мною предлагаются. -------- На всякий случай, по пункту 2: Есть вариант его реализации таким образом. чтобы сохранить существующий интерфейс QLua c QUIK, с тем, чтобы пользователям не надо было изменять существующие скрипты. Это вызов функций обработки коллбеков в видоизмененной sleep с параметрами в нужном формате, считанными из предлагаемых очередей (очереди).
Serge123 написал: Тогда посмотрите на кусочек от вывода моего Луа скрипта, который обрабатывал OnAllTrade от 4 января 2023 г.:
Я согласен с тем, что написал Nikolay. Но если вы хотите разобраться с тем как вызываются коллбеки OnAllTrade реально, то в ваш вывод нужно добавить колонку времен вызова этого коллбека (используя функцию QLua os.sysdate() с детализацией до микросекунд).
Serge123 написал: Тут дело не в том, что есть запись на диск, а в том, что за 1 мкс десятки раз может выполняться оператор
Где вы обнаружили коллбеки QUIK, вызываемые десятки раз за 1 мкс? Не знаю, будет ли для вас это существенно, но одна из моих практических профессиональных специализаций: параллельное программирование и разработка систем реального времени. Возможно я ошибаюсь, но у меня возникло представление, что вы пытаетесь бороться с привидениями, многие из которых у вас не материализуются .
Serge123 написал: Есть строка mess (age), в которой коллбэки накапливают свой вывод, при превышении определённой длины строка записывается в файл.
Почему бы не записывать строку сразу в файл (в системе это буферизуется). Вы проверяли, сколько записей выполняется в файл за 1 секунду, если писать напрямую? Если вы это сделаете, то, возможно, удивитесь. Вообще то, если для вас важна эффективность, то имеет смысл, прежде чем заниматься оптимизацией, выяснять: а нужно ли это делать. Эффективнее всего выполняется то, что ничего не делает .
2.
Цитата
Serge123 написал: Мне кажется, что ничего не случится, если извне (из длл) строка будет изменена, ведь, если строка не находится внутри таблицы, вычисление хеша от неё не нужно?
Если нет желания заниматься длительной научно-исследовательской деятельностью, то для взаимодействия dll и Lua надо использовать только C API. ------ И «перегруженный» анекдот про чукчу: Чукча и геолог ловят рыбу зимой на льду. Геолог приехал на рыбалку на снегоходе, а чукча пришел на лыжах. Вдруг видят направляющегося к ним голодного белого медведя. Ружья нет. Чукча хватает лыжи и начинает их надевать. Геолог: - Бесполезно. Все равно ты не сможешь бежать быстрее медведя. - А мне и не надо бежать быстрее медведя. Мне достаточно того, что медведь сюда добежит раньше, чем ты заведешь свой быстро бегающий снегоход.
Constantin написал: Как я понимаю человек предлагает вызывать колбеки в потоке Lua-скрипта.
Один из возможных вариантов предлагаемой обработки событий Qlua: 1) вместо регистрации функций обратного вызова, регистрация соответствующих потокобезопасных очередей событий (возможно, с теми же именами); я бы сделал эти очереди (можно, в принципе, обойтись и одной) циклическими, с указанием их длины при регистрации, но не более некоторого значения; 2) вместо sleep, служебная функция с тем же именем ожидания либо истечения интервала времени (как в sleep), либо появления данных в очередях событий (с выдачей списка непустых очередей); 3) добавление функции чтения очередей событий (их параметров). Эта схема реализует рекомендованную ARQA обработку параметров событий в main (смотрите "Использование Lua в Рабочем месте QUIK"), с тем, чтобы не было проблем синхронизации в скриптах. Кроме того, в такой схеме решается тяжелая задача подключения новых версий Lua в QUIK, так как не будет требоваться конфигурирования Lua для многопоточного использования (из-за запуска функций коллбеков в потоке, отличном от потока main, но в контексте пользователя). Подключение новых версий Lua в QUIK станет в описанной выше схеме рутинной задачей.
nikolz написал: Вам не нравиться ,что в основном потоке терминала выполняется:запуск всех Lua Скриптов пользователя.--------------И что в этом плохого?
Это мелочь, но при условии, что пакеты в скриптах подключаются в потоке main. Иначе одновременный запуск нескольких скриптов выполняется долго (из-за того, что это это выполняется в одном потоке).
2.
Цитата
nikolz написал: Мое мнение:Колбеки не запускаются, а вызываются.
Пусть для вас вызывается, а для меня запускается . Кому непонятно, что это одно и тоже?
3. По остальной части вашего комментария: Пользовательские индикаторы в графиках обрабатываются в основном (единственном) потоке. Это медицинский факт. Если вы не знаете как это проверить экспериментально, то я вам расскажу как это сделать. дополнительно, в основном (единственном) потоке запускаются коллбеки всех скриптов пользователя, а также вызываются коллбеки всех таблиц QUIK, созданных пользователем. Наверное, понятно и ежу, что в текущий момент в одном потоке все это будет выполняться последовательно. Это значит, что на архитектурном уровне QUIK в текущий момент существует зависимость по выполнению для его различных функциональностей, что является некоторым дефектом. Кому это непонятно?
3.
Цитата
TGB написал: Вы, похоже, очень наивны и полагаете, что разработчики работают за бесплатно? Можно, наверное как то сообразить, что часть комиссии, уплачиваемая брокерам пользователями, идет на зарплату разработчикам, а также в доход акционерам ARQA.
VPM написал: получается что нужно отказаться от отдельного потока main и выполнение main разместить в основном потоке , при этом создав "активную очередь событий".
Я этого не писал. ------- Вообще то, не хочу вас, обидеть, но в моем сообщении пункты 1) и 2) написаны не для либеза. Думаю, что разработчикам QUIK понятно о чем я пишу в этих пунктах.
Где вы у меня прочитали, что все запущенные пользовательские скрипты работают в одном потоке? У меня написано:
Цитата
TGB написал: В текущей версии в одном основном потоке обслуживаются: - запуск всех Lua-скриптов пользователя; - запуск коллбеков всех Lua-скриптов пользователя; - обработка всех коллбеков таблиц QUIK (это не таблицы Lua); - обработка всех индикаторов пользователя.
Вам до сих пор неизвестно, что в QUIK существует служебный, так называемый основной единственный поток, выполняющий то, что перечислено мною выше? Когда же вы научитесь читать чужие сообщения?
2.
Цитата
nikolz написал: Разработчики дали решение этой проблемы. Оно прекрасно работает. Так как QUIK - это бесплатное приложение, то дареному в... не заглядывают. сделать что-то еще - это их право, но не обязанность.
Вы, похоже, очень наивны и полагаете, что разработчики работают за бесплатно? Можно, наверное как то сообразить, что часть комиссии, уплачиваемая брокерам пользователями, идет на зарплату разработчикам, а также в доход акционерам ARQA.
В Новосибирске, когда то была хорошая школа IT-шников. И что-то, наверное, от нее осталось. Я надеюсь, что архитектором QUIK в текущий момент является один из выпускников этой школы. В QUIK все равно будут вноситься изменения (чтобы оставаться «наплаву»). И мне видится, что улучшить QUIK, помимо исправления существующих, неизбежных ошибок, можно внеся в него следующие изменения/дополнения: 1) В текущей версии в одном основном потоке обслуживаются: - запуск всех Lua-скриптов пользователя; - запуск коллбеков всех Lua-скриптов пользователя; -- обработка всех коллбеков таблиц QUIK (это не таблицы Lua); -- обработка всех индикаторов пользователя. Притом, что в текущий момент у подавляющего количества ПК много ядер ЦП, написанное выше явный перебор. Мне, представляется, что нет проблем перечисленное выше обрабатывать в отдельных потоках. Иначе, это ограничение пользователя в использовании возможностей его ПК. 2) Интерфейс взаимодействия QUIK c Lua-скриптом пользователя, реализованный в виде коллбекков, предполагает многопоточный режим использования Lua,. порождающий неприятные проблемы параллельного программирования (для решения которых сами же разработчики предлагают использовать потокобезопасную очередь между коллбеками и потоком main). Мне представляется, что имеет смысл вместо коллбеков использовать активную очередь событий, При этом не требуется использовать Lua в многопоточном, редко используемом и не очень стабильном режиме. При этом не будет проблем с подключением новых версий Lua. Более того, скрипты пользователя будут выполняться несколько быстрее из-за отсутствия синхронизации, требуемой в многопоточном варианте использования Lua. 3) В QUIK реализована функциональность просмотра графика котировок бумаг QUIK. Но отсутствует возможность просмотра котировок бумаг, сохраненных во внешних файлах. С учетом существующей функциональности QUIK, как мне представляется, реализация этой возможности не потребует больших усилий.
nikolz написал: Мне даже показалось, что вы имеете отношение к этому сайту.
Действительно на этом сайте я написал несколько заметок. И когда я начал в 2019 г. разбираться с QUIK, то обнаружил, что для меня это самый полезный сайт. Но я в своем сообщении сослался не на ту заметку, про которую вы пишите, а на "Краткую справку по Lua", в которой, кстати есть и описание C API Lua с примерами. На этом же сайте есть как минимум один функционально законченный пример использования C API Lua от Дмитрия.
2
Цитата
Serge123 написал: А тут мощь dll, которая оттранслирована с оптимизацией и поддержкой наборов вплоть до AVX2, будет кстати.
И вы знаете как использовать эту мощь для получения дохода на рынке с помощью QUIK, обеспечивающего как минимум секундную реакцию на события рынка? Возможно я ошибаюсь, но мне представляется, что вы пытаетесь "запрягать лошадь с хвоста". Вообще то, существует известная и проверенная временем методология разработки программ. Суть этой методологии в том, чтобы быстро получить работающий, модульный прототип и в конкретном случае это проще сделать используя Lua (а при необходимости готовые пакеты dll). А дальше выяснять проблемы (в том числе и с производительностью) и вносить изменения. С учетом того что Lua тесно интегрирован с C/C++ проблем с переходом из Lua в C нет, но это может и не потребоваться.
Serge123 написал: Прямого ответа обычно не дают, а как-то ходят вокруг да около этого вопроса...
На форуме много сообщений о том, что не надо писать сложно. Надо писать модульно, стараясь не создавать "зоопарк" программных средств , чтобы потом не было больших проблем с неизбежными изменениями. Практически любого робота для QUIK можно написать используя только Qlua (Lua). В сети есть много описаний (достаточно коротких) о том, что собой представляют таблицы Lua и как с ними можно работать (например, на сайте https://forum.quik.ru/ выложена краткая справка по Lua). Зачем вы мучаетесь с C API Lua? Что вы не можете сделать в Qlua (Lua)?
Владимир написал: А ограничивать это НУЖНО! Софт и так на ладан дышит
Не заметил проблем с производительностью. Действительно, ни микросекунды, ни тысячи тикеров, ни параллельные потоки, если кто понимает, не нужны. Для индивидуалов вполне можно обойтись несколькими десятками тикеров и реакцией в секунды. Тем более, что QUIK не позиционируется для безумной высокочастотной торговли.
Владимир написал: КАКОМУ ДЕБИЛУ понадобился "расчёт количества лотов конкретного инструмента с учётом состояния портфеля"? При чём тут плечи и вообще брокеры? Какое моё собачье дело до ИХ "представлений о рисках предоставления плеч для разных инструментов и разных в разное время"? На кой мне "максимально возможное количество лотов в заявке"?
Ну, не все же гениальные как вы . И какой то дебил это хочет знать. Ну и пусть. Зачем кого то ограничивать при наличии своих неограниченных способностей ?
Владимир написал: Если чел не способен самостоятельно посчитать такую ерунду, его надо поганой метлой гнать из программирования.
Мысль интересная . Я не умею считать такую ерунду. Пожалуйста, напишите формулу расчета количества лотов конкретного инструмента с учетом состояния вашего текущего портфеля, с учетом допустимых плеч у брокеров, зависящих об их конкретных представлений о рисках предоставления плеч (возможно, разных для покупки и шорта, разных для разных инструментов и разных в разное время). Если бы я знал риски брокеров по инструментам, то такую формулу бы написал. Вы экстрасенс ?
Читайте документацию. Там написано, что операция # применима только для строк и таблиц-массивов (это такие, в которых индексы строго от 1 до N без пропусков).
nikolz написал: Херня это все У вас очередь - это массив. Если в массиве хранятся числа, то для них не отводится дополнительной памяти. Но даже если Вы храните указатель, то сам элемент массива останется в памяти. Запись nil - это запись 0 в тип элемента массива. Элементы массива никуда не денутся пока Вы не уничтожите весь массив путем записи nil в его имя. а не в его элементы.
Вы до сих пор не поняли что?:
Цитата
TGB написал: 1. Под все данные, создаваемые непосредственно в Lua, память выделяется автоматически. Память, занимаемая неиспользуемыми (недостижимыми из скрипта: для сильно непонятливых это области данных недоступные из него) данными Lua, освобождается также автоматически (при сборке мусора).
2. Где вы у меня прочитали, что я пишу про элементы массива? Вы до сих пор не научились читать ? 3. Запись nil - это не запись 0 в тип элемента массива, а запись в скрипте nil в поле массива. При такой записи элемент массива становится не доступным. Если умеете читать, то почитайте документацию на Lua. 4. Заодно ответ на ваш вопрос в ветке об os.sysdate(). Ваша формула: local tim=60.*(60. * T.hour + T.min) + T.sec + 0.001*(T.ms + 0.001*T.mcs) неправильная. Правильно: local tim=60.*(60. * T.hour + T.min) + T.sec + 0.001*(0.001*T.mcs) Давно бы распечатали результат вызова os.sysdate(). os.sysdate() выдает таблицу о текущей дате в следующем виде: -- [day] (number) = 28 -- [hour] (number) = 19 -- [mcs] (number) = 719755 -- мкс. --- #### Это поле не является дополнением к полю ms -- [min] (number) = 46 -- [month] (number) = 11 -- [ms] (number) = 719 -- млс. --- #### -- [sec] (number) = 6 -- [week_day] (number) = 2 -- [year] (number) = 2023
Владимир написал: TGB , Я не просто думаю - я в этом уверен!
Эксперимент в QLua (можете повторить): tbl = {1, 2, 3} message (tostring (tbl)) -- Результат: table: 0000024208D734F0 - это ссылка на таблицу -- tbl = {1, 2, 3} message (tostring (tbl)) -- Результат: table: 0000024208D727F0 - это ссылка на другую таблицу -- ---- Ваш стек это, наверняка, некоторая таблица, и вы туда пишите, наверное, не только числа, но возможно строки и таблицы, которые вы где то создаете или получает. И строки и таблицы в Lua не перезаписываются. Если есть сомнения, то можете в своем скрипте отключить мусорщик следующим образом: collectgarbage('stop') чтобы под ногами не путался .
Владимир написал: При следующем всплеске активности скрипт просто перезабьёт новые данные в старые элементы - память под них уже выделена. А мусорщик сидит и молчит в тряпочку, а не путается под ногами. Сказка!
Вы думаете, что если было выражение: tbl = {1, 2, 3} а вы потом вы написали еще раз tbl = {1, 2, 3}, то будет перезаписана область памяти из под первой таблицы?
VPM написал: А что если просто перезаписывать, я про пример из 5 элементов? nil будет вызывать сборщик, а перезапись ну поменял элемент объем остался прежним?
При перезаписи, если нет других ссылок на область памяти, то она будет удалена (почищена) мусорщиком. Под все данные, создаваемые непосредственно в Lua, память выделяется автоматически. Память, занимаемая неиспользуемыми (недостижимыми из скрипта) данными Lua, освобождается также автоматически (при сборке мусора).
VPM написал: подход максимальной локализации переменных, и по блочному их использованию, для таких пользователей как я оптимальный. И можно забыть про такое _G
VPM написал: "наделав кучу на голове у оппонента, сидеть на ней, как на горе Эверест, со значимым видом"
Довольно остроумное предложение по переименованию большей, но не лучшей части данной ветки .
2.
Цитата
VPM написал: Здесь вопрос вот в чем, зачем здесь глобальная таблица со своим окружением
Если внимательно читать автора, то в переводе на простой язык написано следующее. У скрипта существует внешняя служебная переменная с именем _ENV (доступная программисту). Все <переменные скрипта>, без спецификации local (называемые переменными окружения), семантически (по смыслу) эквивалентны: _ENV.<переменная скрипта>. То есть, предполагается, что значением _ENV может быть (вообще говоря, любая) таблица. По умолчанию при запуске скрипта, _ENV автоматически присваивается глобальная служебная таблица _G (тип table), в которой первоначально хранятся стандартные функции Lua. Переменные окружения скрипта будут ключами этой таблицы. Поэтому (если не присваивать _ENV таблицу отличную от _G) запись в скрипте: val = 1 эквивалентна следующей записи (_ENV.val =1) _G.val =1 или (_ENV['val'] =1) _G['val'] = 1. Если же не заморачиваться деталями реализации Lua, описанными выше, и не трогать _ENV , то достаточно понимать, что все переменные скрипта без спецификации local являются ключами некоторой служебной таблицы, и экзотическими способами обращения к таким переменным не пользоваться.
Quikos_1 написал: type:string:1 //Таблица глобальных функций
Ну, если это таблица, то я сдаюсь и "умываю руки" . Похоже, вы долго будете развлекаться отладкой. Потом, просьба к вам, сообщить конечный результат в этой ветке.
Quikos_1 написал: Это так не работает, если только Вы монолог сами с собой не ведете.
Учел вашу критику .
1.
Цитата
Quikos_1 написал: Ох, Вы явно путаете сборку мусора оперативной памяти и рабочую структура стека Lua. Они ни как не связаны.
Сначала некоторое утверждение, а затем конкретный вопрос: 1) При уборке мусора просматриваются объекты скрипта и ищутся такие, на которые нет ссылок из среды выполнения скрипта. 2) Если в стеке скрипта, в момент работы мусорщика, находится ссылка на какую то таблицу и на нее нет других ссылок, то как мусорщик определит, что эта таблица «живая», не обрабатывая стек?
: 1) Ошибка: Оператор if (status_lua_pcall != 0) ловит только исключения. Функция . CreateDataSource обычно завершается, не выбрасывая исключение, даже если источник не создан. Надо анализировать результат выполнения CreateDataSource. Если источник не создан, то первое значение результата nil, а второй результат: строка описания ошибки создания источника. Похоже, вы запускаете свой скрипт в песочнице, а там класс для SBER не TQBR. У вас не создался источник свечей.
Quikos_1 написал: ВОПРОС: КТО И ЗАЧЕМ очитстил стек ?? КАК видно из кода, между вызовов SetUpdateCallback и вызовом самой колбек-функции нет ни одной строчки кода, которая бы редактировала стек. Так что происходит тогда ?
Quikos_1 написал: ВОПРОС: КТО И ЗАЧЕМ очитстил стек ?? КАК видно из кода, между вызовов SetUpdateCallback и вызовом самой колбек-функции нет ни одной строчки кода, которая бы редактировала стек. Так что происходит тогда ?
1. На форуме много раз отмечалось, что если нужен результат, а не развлечение отладкой, то писать скрипты надо просто. Что-то использовать кроме QLua, надо в крайнем случае (в том числе C-API), если, действительно, QLua и многочисленных пакетов Lua не хватает для реализации задуманного. 2. Зачем вы используете C-AP? Что вам не хватает в Qlua? 3. В Qlua, как известно, автоматическая память и сборка мусора может быть запущена как внутри вызова C-API, так и при вызове коллбека, в основном отдельном параллельном потоке QUIK. Мусорщик работает по всем таблицам и стекам lua_State и что-то там делает.
Serge123 написал: Теперь меня интересует, как получать в длл таблицы от луа и разбирать их, напр., таблицу заявок и обезличенных сделок. Я несколько лет назад перешёл с Дельфи 7 на си под 64 бит и gcc, теперь неохота сидеть на 2-х стульях.
Я согласен с тем, что выше написал swerg. От себя добавлю: возможно, для вас окажется полезным сайт https://quikluacsharp.ru/ , на котором есть много чего интересного, в том числе "КРАТКАЯ СПРАВКА ПО ЯЗЫКУ LUA.PDF", написанная мною. В ней есть описание трансляции C++ dll для Lua, а также краткое описание C-API Lua.
nikolz написал: Это важно, поскольку позволяет рассчитать доверительный интервал для коэффициента корреляции Пирсона.
Давно не заходил на форум. Интересно, у кого представления, что фондовый рынок описывается вероятностной моделью, для которой имеют реальный смысл ее характеристики. Понятно, что если нет хорошей модели рынка, то можно брать за основу и вероятностную. Но, кто понимает, то это большая "натяжка". У меня нет такой убедительной модели, но, если бы она была, то должна бы была учитывать пирамидальное поведение "толпы" рвущейся за прибылью, а также наличие инсайдерских каналов. Это точно не вероятностная модель.
VPM написал: Вот это совсем не понял? можно своими словами попроще.
Попроще. QLua это форк Lua, скомпилированный в режим использования стеков сопрограмм (thread) в отдельных потоках. Колбеки QLua запускаются в потоке отличном от пользовательского потока main. Для функций стандартных библиотек QLua нет гарантии на уровне архитектуры реализации языка, того, что они потокобезопасны для упомянутого режима. Например, пользователь Старатель обнаружил "мерцающую" ошибку в tonumber (https://forum.quik.ru/messages/forum10/message57110/topic5823/#message57110), которая, скорее всего, подтверждает вышенаписанное.
Владимир написал: Lua всё реализовано через жопу (я в своё время чуть в обморок не упал, когда увидел на этом месте ФУНКЦИЮ вроде bit.band), то хрен его знает - до ТАКОГО способны додуматься только клинически криворукие, и реализвция может быть ЛЮБОГО уровня тупости.
Несколько слов возражения (написанных мною когда-то) Краткая характеристика Lua Lua - интерпретатор динамический: переменным можно присваивать данные любого типа Lua. Данные языка имеют свойство Тип. Контроль типов данных выполняется только в момент исполнения скрипта Lua. По сути, Lua двухуровневый язык программирования: Lua/C. Эта двухуровневость была заложена в проект языка и реализована изначально (Lua тесно интегрирован с C/C++). С учетом этого, функциональность, разрабатываемых на Lua программ и их эффективность, фактически определяется возможностями C/C++. Исходный код скрипта на Lua транслируется в байт-код либо предварительно, либо непосредственно в начале выполнения скрипта. Байт-код выполняется виртуальной ма-шиной Lua. Управление памятью автоматическое, с использованием потокоопасного мусорщика. Функционально все (исключая параллелизм выполнения его функций) можно написать на «чистом» Lua, но при необходимости, из Lua можно легко перейти в C/C++ (используя все его возможности) и вернуться обратно. Lua очень компактный как по коду его реализации, так и по его описанию, достаточного для его начального использования. Особенно это заметно на фоне многочисленных монструозных средств разработки программ. Пожалуй, отношение <функциональности Lua> к <его компактности> одно из самых высоких среди известных языков программи-рования. Для хорошего понимания Lua необходимо четкое представление об устройстве его ассоциативных таблиц (тип table), элементами которых являются неупорядоченные пары: <Ключ таблицы (данные любого типа Lua кроме nil)> <Поле таблицы (данные любого типа Lua кроме nil, при присвоении которого полю, соответствующая запись таблицы удаляется>. Доступ к полям таблицы выполняется по ее ключам. Таблица используется, в том числе, и для хранения всех переменных окружения Lua (переменных, без спецификации локализации: local). Имена этих переменных всего лишь ключи, а данные переменных - поля этой глобальной таблицы (видимой из любого места скрипта). В Lua используются переменные двух видов: локальные переменные и переменные окружения (общие для всего скрипта и описываемое далее). Локальные переменные имеют блочную лексическую область видимости (в тексте кода видится только то, что создано/объявлено ранее во внешних или текущем блоке, а повторно объявленное все-гда экранирует предыдущее с учетом блочной структуры скрипта). Видимость переменных окружения (в таблице окружения) из некоторого места скрипта определяется выполнением обращения к переменным/ключам таблицы окружения (доступной в любом месте скрипта) не экранированных из этого места локальными переменными. Рекомендуется там, где это возможно, использовать локальные переменные, объявляемые со спецификацией: local <Список локальных переменных>. Эти переменные хранятся в стеках блоков Lua и обращение к ним эффективнее, чем к переменным окружения. При выходе из любого блока, его локальные переменные перестают существовать. Типы данных полей таблиц Lua это: - значения: nil, boolean , number, string; - ссылочные данные: function, thread, table, userdata. При присвоении значения копируются, а на ссылочные данные создаются ссылки. На одно и то же ссылочное данное может быть несколько одинаковых ссылок из разных переменных. Функции (function) в Lua анонимные (данные первого класса, при присвоении и других базовых операций не отличающиеся от остальных ссылочных данных Lua), не имеющие встроенных имен для обращения к ним. Существует конструктор создания функции с присвоением переменной ссылки на нее. Вариантом конструктора функции является строка с текстом скрипта, из которой может быть создана функция скрипта с использованием служебной функции Lua. Любую функцию Lua можно вызвать на исполнение с использованием тех переменных, в которых есть ссылка на нее. Как и остальные ссылочные данные, функции, если в процессе выполнения скрипта на них нет ни одной ссылки, подпадают под уборку мусорщиком Lua. Функцией является сам скрипт Lua. Функция может быть создана/определена внутри любой функции в любом месте и может быть выдана как результат функции. Результатов у функции может быть больше одного. В функциях обеспечивается рекурсия, а также они представляют собой замыкания (в них допускается использование локальных переменных тех блоков, внутри которых создаются функции и которые (внешние локальные переменные,) являются составной частью функций – ее внешним локальным окружением). При создании функции, в том числе и в качестве результата некоторой функции, она создается с состоянием своего внешнего локального окружения, имеющегося на момент ее создания. Строки (string) в Lua битовые (в байтах строки могут быть любые комбинации 1 и 0), семантически являются значениями (внутренне неизменяемыми после их создания, копируемыми при присвоении) и у них есть свойство длина строки. Символ ‘\0’ не является признаком конца строки. Более детально все типы Lua описаны в основном тексте справки. Окружение скрипта Lua определяется (начиная с версии 5.2) служебной переменной _ENV (по умолчанию ссылающуюся на глобальную служебную таблицу _G), которой можно присвоить в скрипте ссылку на любую доступную таблицу Lua. После такого присвоения, окружением скрипта станет присвоенная таблица. Таблицы в Lua можно использовать как метатаблицы. Это таблицы Lua, которые: 1) подключаются служебным оператором подключения метатаблицы к таблице (в том числе можно и к любой метатаблице или к самой себе); 2) при определенных операциях над таблицами (у которых есть метатаблицы) или ситуациях, возникающих при их использовании, Lua обрабатывает служебные ключи (с преопределенными именами) метатаблиц специальным образом (например, запускаются функции, ссылки на которые присвоены полям таких ключей и т.д.). В Lua можно использовать сопрограммы: тип thread. Они запускаются в отдельных стеках сопрограмм (thread) и в стандартной конфигурации Lua реализуют псевдопото-ки (нити, обслуживаемые одним потоком). В сопрограммах обеспечивается режим вызова функции с возможностью ее продолжения после программного прерывания, вызываемого с помощью служебной функции yield. -- Отдельные стеки сопрограмм реентерабельны и могли бы выполняться в различных потоках, но так как сборка мусора потокоопасная, то в нескольких потоках Lua можно использовать только как разделяемый ресурс под синхронизацией (в специальной конфигурации-сборки Lua). Это относится и к его функциям C-API, являющиеся частью Lua.. При компиляции интерпретатора Lua есть возможность указания режима использования стеков сопрограмм (thread), под синхронизацией, в отдельных потоках. При этом, C-функции, запускаемые в различных стеках, могут выполняться (в разных потоках) параллельно, но код Lua может выполняться в потоках только в разделяемом режиме (под синхронизацией). --- В переводе на другие известные языки ООП: таблицы Lua это динамический список свойств и ее методов (заданных в том числе и в их метатаблицах), связанных с этими свойствами. Профессионал, наверное, сможет изучить этот язык, почти в полном объеме, дня за два-три. Для начинающих программировать это язык в своей основе (без использования средств ООП) тоже, наверное, один из самых простых. Если делать в программах на Lua проверку типов параметров (а может быть и областей значений) более-менее содержательных функций, то можно обеспечить и надежность разрабатываемых на Lua программ. --- Код реализации Lua всего: ~400kb. Доступный исходный код Lua может служить одним из примеров того, как можно/нужно программировать на языке C. ----- Несколько общих замечаний относительно Lua: 1) Нотация записи программ не последнее дело и авторы языка зря не использовали проверенную временем нотацию C/C++, как в части записи кода, так и в напи-сании комментариев. Конструктор таблиц можно было при этом представить, на-пример, в виде: <….>. Как представляется издалека, сишная нотация Lua, обес-печила бы ему гораздо большую популярность среди программистов, чем это есть сейчас. Показательным подтверждением написанного выше, является язык python. В нем была выбрана нотация записи программ, которая «зашла» многим пользователям(психология восприятия текстов человеком) и этот язык, использующий многие архитектурные решения Lua (как и Java-sript, появившийся на 2 года позже Lua), стал популярным. 2) Множественное присвоение в Lua, а также, возможные, множественные значения результата его функций обеспечивают дополнитильную гибкость (вариантность) написания скриптов Lua, однако, являются существенными потенциальны-ми источниками ошибок в них, так как семантика реализация этой множественности слабо отражается в синтаксисе ее записи и это надо контролировать на семантическом уровне (например, если в параметрах функции1 есть вызов функции2, то в качестве параметров могут вставиться несколько значений функции2, но сколько их будет, из имени функции2 формально это не следует). 3) Влючительно до версии 5.4.1, в кодах стандартных библиотек Lua не был учтен существующий режим конфигурирования (предусмотренный в исходниках Lua) использования стеков сопрограмм (thread) в отдельных потоках. Функции стандартных библиотек определены в Lua как сишные (потокобезопасные, допускающие параллельное выолнение), но в их коде нередко используется внутренняя среда интерпретатора Lua (не являющаяся потокобезопасной), и нет гарантии на уровне архитектуры реализации языка, того, что стандартные функции Lua по-токобезопасны для упомянутого режима. 4) Синтаксис Lua простой: основная его сложность перенесена в функциональ-ность его таблиц, реализованных на C. Поэтому трансляция текстого кода Lua в его исполняемый байт-код, реализована эффективно, и это надо учитывать и ис-пользовать при написании скриптов на Lua (понимая возможность динамического создания текстов-скриптов внутри выполняемого скрипта). 5) Выбор в Lua фактически единственного, но универсального типа table, обеспечивающего его полную функциональность, позволяет кратко записывать семантику выполнения скриптов. Кроме того, короткий технологический цикл, от написания кода, до его запуска, обеспечивает оперативное получение конечного результата. Интеграция Lua с C/C++ обеспечивает его расширяемость, как в части использования существующих библиотек, так и в части эффективности выполнения его скриптов. При этом надо учитывать то, что динамизм Lua потенциально отрицательно влияет на надежность кодов, написанных непосредственно на нем.