Средства разработки многопоточных скриптов в QUIK., OS_Quesha, свидетельство регистрации в Роспатенте № RU 2020612905. Бесплатная для некоммерческого использования.
Александр М написал: Большинство перечисленных пунктов в "Основные функции OS_Quesha." решаются в виде простого lua скрипта, включая и графические интерфейсы
Когда обсуждаются любые средства, облегчающие разработку программ, возражение типа: «Это можно сделать существующими средствами», «не катит», так как, в конце концов, все можно сделать и на ассемблере. По существу же, обсуждать имеет смысл то, насколько быстро и качественно можно разрабатывать приложения, использую предлагаемые средства по сравнению с тем, что обеспечивают существующие средства их разработки. Конечно, только практика использования любого средства разработки программ может определить его реальную полезность для разработчиков. Такая возможность разработчикам роботов в QUiK предоставлена в виде кодов и документации OS_Quesha.
Цитата
Александр М написал: Очень специфическое возможное использование, я даже не смог придумать сходу, где бы мне это решение понадобилось с учетом всех реализованных мною проектов, включая заказные
Мне непонятно в чем состоит специфичность использования OS_Quesha, если вместо одной функции main в QLua, в OS_Quesha, при использовании исходника TS_QUIK_RT.lua, предоставляется четыре (количество определяется в исходнике, в описании схемы обработки в табличном виде), аналогичные функции, в которых доступен весь API QLua. Эти функции могут, при наличии нескольких ядер в ЦП компьютера, выполняться параллельно (с учетом особенностей версий QUIK > 8.4, описанных в моем начальном комментарии). Дополнительно они могут взаимодействовать между собой через готовые очереди. Кроме того, в них доступны все возможности, описанные в моем начальном комментарии. Причем, расход ресурсов ПК на функционирование OS_Quesha ничтожен и в этом можно убедиться, запустив немодифицированный исходник TS_QUIK_RT.lua. Все дополнительное использовать не обязательно, но это может потребоваться при последующем расширении возможностей робота.
Поскольку Вы спрашивали у меня, то отвечаю.
У разработчика уже есть готовые набор библиотек, каркасы роботов, индикаторов и т.д. из которых он собирает продукт. Все это переделывать на ЧУЖУЮ библиотеку: 1. Непонятно зачем, т.к. уже есть свое и готовое. 2. Опасно.
Возможно Ваш продукт заинтересует новых разработчиков, которые только только хотят что-то сделать, и им для этого обязательно понадобилась параллельная работа нескольких скриптов с общей очередью (достаточно сложный проект). Такое сочетание факторов достаточно редкое, поэтому я и написал про "специфичность".
Конечные пользователи Ваш продукт просто не потянут для написания на нем чего либо.
Александр М написал: У разработчика уже есть готовые набор библиотек, каркасы роботов, индикаторов и т.д. из которых он собирает продукт. Все это переделывать на ЧУЖУЮ библиотеку:1. Непонятно зачем, т.к. уже есть свое и готовое.2. Опасно.
Я, во многом, согласен с выше написанным относительно разработчиков, давно работающими над внешними проектами. Но среди большого количества пользователей, по моему представлению (основанным на моем опыте), найдутся те (их будет очень мало), кому это будет интересно и кто способен в этом быстро разобраться и использовать. И мне интересны такие пользователи. Кроме того, представленное мною (некоторая готовая инфраструктура создания роботов, которая создавалась для решения собственных задач) может вдруг показаться полезной и профессиональным разработчикам.
Целую страницу постов а-ля "нинужно, кг/ам" нафлудили. Вам нинужно, а кому-то может интересно будет. Та же is-odd.js как ни абсурдно имеет астрономическую популярность (справедливости ради, широта языка не распологает к инлайн-исполнению таких вещей).
Вопрос к автору: какой такой сценарий в контексте брокерского торгового терминала предпологает "некоммерческое" использование?
Артем написал: какой такой сценарий в контексте брокерского торгового терминала предпологает "некоммерческое" использование?
Некоммерческое использование это значит, что любое частное лицо (пользователь) может использовать обсуждаемые средства (в том виде как они есть, без гарантии последующей их поддержки с моей стороны) для создания своего робота.
Артем написал: какой такой сценарий в контексте брокерского торгового терминала предпологает "некоммерческое" использование?
Некоммерческое использование это значит, что любое частное лицо (пользователь) может использовать обсуждаемые средства (в том виде как они есть, без гарантии последующей их поддержки с моей стороны) для создания своего робота.
Создаешь с помощью вашего фреймворка робота который будет торговать и зарабатывать деньги - тут налицо коммерческое использование. Логически, любая утилита для торгового терминала по-умолчанию будет использоваться коммерчески так как у торгового терминала есть только коммерческий функционал.
С точки зрения ГК коммерческая деятельность - это деятельность предприятия (организации, юридического образования) направленную на рыночную деятельность, имеющую своей целью получение прибыли или рыночного дохода.
Так что это не о том.
А по существу уже все обсудили. Я слабо себе могу представить разработчика, использующего библиотеки без исходных кодов.
qlua.dll - это библиотека, неотъемлемая от терминала. Так что ее можно считать частью среды исполнения. Я же говорю о библиотеках реализующие часть функциональности, которую можно реализовать самому. Предпочтение будет всегда тем, которые имеют открытый код.
Владимир, как угодно. Можете доверять чужим рукам.
Nikolay, И ничему не доверяю. Просто трудоёмкость разбирательства в чужом коде соизмерима с разработкой аналогичного продукта с нуля. А иногда и выше.
я вот сейчас отлаживаю свой алгоритм снятия заявок. Там и так чёрт ногу сломит, но ещё и напоролся на дополнительную чертовщину: у меня ID транзакции с самого начала задавалось как: A.TRANS_ID=tostring(math.random(1,9999)); Я это дело никогда даже и не проверял - работает и работает. А сейчас мне нужно по нему в некоторых случаях определять ID заявки в таблице orders,так я вывел отладочную печать, гляжу, а там TRANS_ID=13. Второй раз запускаю - опять 13.У второго брокера на другом Квике сработала - опять 13! То ли лыжи не едут...
Если id транзакции предполагается в дальнейшем использовать как ключ, то необходимо обеспечить его уникальность. Хоть рандомизация и повышает вероятность уникальности, но не обеспечивает ее в полной мере. Чаще всего используют производные от unix-time как ключ транзакции. Но при этом надо еще подумать об уникальности между скриптами, т.к. вероятность отправки транзакции двумя скриптами одновременно есть.
Nikolay, Я понимаю. Просто я предполагал, что ключи юзеровских транзакций уж как-нибудь не повторятся за сеанс при задании таким способом (я его откуда-то списал, из какого-то примера). А сегодня как посмотрел...
А как "нормальные люди" задают ID транзакции? В принципе, можно бы присобачить системное время или просто нумеровать их у себя как 1, 2, 3, 4,... А "уникальность между скриптами" меня не волнует - у меня один скрипт - есть, был и будет. Точнее, две его копии на двух Квиках.
Владимир написал: или просто нумеровать их у себя как 1, 2, 3, 4,...
Если у вашего робота не предусмотрен перезапуск с продолжением с прерванного места, то это самое подходящее. Если же перезапуск предусмотрен, то необходимо предусмотреть и продолжение нумерации после перезапуска (с сохранением ее последнего значения в энергонезависимой памяти).
TGB, Это не проблема: результаты у меня по выходу записываются в файл, а по запуску читаются, так что можно этот счётчик сбрасывать и потом читать - прямо как оператор Lua через loadstring. Я так и делаю для сумм свободной налички по валютам, номера счёта, кода клиента и ещё для чего-то. Только ведь это стандартнейшая операция! Это же делают все без исключения! Неужели нет чего-то без сохранения? Примерно такого, чего я ожидал от math.random. По-нормальному это вообще должно бы быть возвращаемое значение, как с файлом или диспетчером памяти: возвращаем дескриптор - и всё!
Владимир написал: А как "нормальные люди" задают ID транзакции? В принципе, можно бы присобачить системное время или просто нумеровать их у себя как 1, 2, 3, 4,... А "уникальность между скриптами" меня не волнует - у меня один скрипт - есть, был и будет. Точнее, две его копии на двух Квиках.
Так и используйте время, как многие делают, зачем этот огород с рандомом? При запуске скрипта задаете начальное значение, типа:
Код
local trans_id = os.time () - 1546290000 -- идентификатор транзакции (количество секунд с начала 2019 года для UTC+3)
или просто os.time (), а дальше в скрипте: trans_id = trans_id+1
У стандартного рандома Lua всего 15 бит собственно рандомности, не считая несовершенство алгоритма генератора - повторы гарантированны с довольно короткой периодичностью.
В догонку: сид рандома надо задавать вручную из какой-то непостоянной величины, которая будет меняться от запуска к запуску. Псевдослучайный рандом, разумеется, всегда выдаёт одинаковую последовательность чисел - если она еще и начинается каждый раз с одного и того же числа, то никакой случайности не будет.
trans_time=dt.hour*10000+dt.min*100+dt.sec -- время отправки транзакции HHMMSS
trans_id_count=(trans_id_count+1)%100 -- счетчик транзакций, от 0 до 99 и по кругу
trans_id=1000*trans_time+100*robot_id+trans_id_count -- Уникальный идентификатор транзакций
Расчет на 10 одновременно работающих роботов, у каждого робота свой robot_id от 0 до 9 В результате чтобы нарушилась уникализация надо одним роботом более 100 раз в секунду транзакцию сделать, что практически невозможно.
Артем, Мало, что ли? Когда я пользовался датчиками случайных чисел, они всегда у меня были 16-разрядными (правда, алгоритм генератора был "совершенный" - два алгоритма генерации псевдослучайной последовательности в случайные моменты времени перещёлкивались друг на друга). А иногда требуется как раз "случайность без случайности" - например, когда я генерил графы для задачи коммивояжёра (с равномерным распределением и с иерархической кластеризацией), то во втором случае у меня была чистая случайность, а вот в первом последовательность "начиналась каждый раз с одного и того же числа", то есть каждый граф большего объёма содержал в начале любой из меньших. Генерил графы от 3 до 123456789 узлов,, проверял - НИ ОДНОГО повтора координат! А здесь что? Обеспечить уникальность транзакций за одну несчастную сессию? У меня их несколько десятков. Ну, сотен - курам на смех! И самое главное - почему обеспечение уникальности идентификаторов транзакций ложится на юзера? Ведь для Квика это просто порядковый номер строки в его таблице - даже искать ничего не надо! Так не проще ли сделать ID=sendTransaction, а в случае неудачи возвращать 0? И волки целы, и овцы сыты.
BlaZed, Во, блин! Что ещё за dt? И что лучше, dt или os.time?
Ага, понятно. Не, я, скорее всего, буду счётчик инициализировать на старте системным временем, а потом инкрементировать и по выходу не сохранять. В общем, так, как подсказал Игорь.
Посмотрел я сейчас на свой код в плане того, чем я пользуюсь из предоставленных возможностей. Картина такая:
1. Файловые операции (open, close, write) - претензий нет. Ну, вместо read сидит какой-то F:lines(), но работает. Не видел, правда, seek, но я его и не искал, он мне не нужен. getScriptPath тоже работает.
2. Работа со строками (find, sub) - претензий нет. Особенно хорош string.format - благо, передран один в один из sprintf.
3. Прерывания (коллбеки). Использую только OnStop и OnTrade как минимально необходимые. Глючат оба: у первого иногда пропадает управление, у второго прерывания приходят пачками. И то и другое вылечил, пользуюсь. Кстати, у меня четверть, если не треть всего кода написана именно для компенсации разных глюков именно поэтому я пользуюсь чистым Lua и крайне неохотно включаю любые "библиотечные" возможности.
4. Работа с окнами (AllocTable, AddColumn, Clear, CreateWindow, DestroyTable, InsertRow, SetCell, SetColor, SetTableNotificationCallback, SetWindowCaption, SetWindowPos). Глючат все (именно обращение к ним в OnStop вызывает потерю управления). Охренел в своё время от необходимости вызова этих функций именно в определённой последовательности, иначе "просто не работает". Вылечил, пользуюсь, терпимо. DeleteRow вообще выкинул нафиг, а редко встречающееся полное исчезновение текста в ячейках таблице лечу по клавише Enter.
5. Преобразование типов (tonumber, tostring) - претензий нет. Но за динамическую типизацию, замену операций булевой алгебры на убожество типа bit.band руки-ноги бы повыдёргивал разработчиком! А уж за убийство типа integer... ТАКОГО маразма я ещё не встречал ни в одном языке - Lua первый!
6. Работа с таблицами (getItem, getNumberOf, getParamEx). Коряво, но работать можно. Первыми двумя пока ещё не пользовался - они нужны только для снятия заявок, для работы только с таблицей "orders", чтобы не использовать глючного OnOrders.
7. Библиотеки. math.random приказал долго жить (вместо него, видимо, появится os.time), а math.floor использую в функции обрезки концевых нулей после запятой (идею подсказали на этом форуме). Убей, не понимаю, что он делает, но работает прекрасно!
8. Стандартные конструкции: с message вопросов нет (alert - он и в Африке alert), sleep используется обычным образом в main (150 мс - при этом задержки реакции на мышку и клаву почти незаметны), а на работу (отсутствующей в описании языка) loadstring просто не нарадуюсь!
BlaZed написал: Расчет на 10 одновременно работающих роботов, у каждого робота свой robot_id от 0 до 9
Есть идеи, как сделать уникальный trans_id в разных роботах без необходимости задавать свой диапазон (robot_id) внутри каждого робота (или их копий)? Вместо trans_id_count можно использовать миллисекунды из os.sysdate(). Но
Цитата
Nikolay написал: вероятность отправки транзакции двумя скриптами одновременно есть.
BlaZed написал: Расчет на 10 одновременно работающих роботов, у каждого робота свой robot_id от 0 до 9
Есть идеи, как сделать уникальный trans_id в разных роботах без необходимости задавать свой диапазон (robot_id) внутри каждого робота (или их копий)? Вместо trans_id_count можно использовать миллисекунды из os.sysdate(). Но
Цитата
Nikolay написал: вероятность отправки транзакции двумя скриптами одновременно есть.
Вопрос уникальности транзакции обычно возникает в свете поиска ответа на транзакцию и установленного ордера по ней, сделок. Обычно делают номер как unix_time + mcs*1000. Также скрипт пишет в поле brokerref свой уникальный комментарий. Или, как выше написали, есть некая добавка от номера скрипта. Я предпочитаю brokerref, т.к. он идет сквозным образом от транзакции в ордер и сделки.
Вместе это дает уникальность при дальнейшем использовании номера и brokerref.
Есть идеи, как сделать уникальный trans_id в разных роботах без необходимости задавать свой диапазон (robot_id) внутри каждого робота (или их копий)?
Я уникальность обеспечиваю фиксированием момента времени включения скрипта, а не совершения транзакции.А уже дальше, если в скрипте есть сделка, то как обычно, к полученному случайному числу +1.
local trans_id_start = os.time () - 1546290000
local trans_id = trans_id_start + getUniqTransID()
Вот так ID должны быть уникальны, независимо от количества запущенных роботов.
Наврал. Надо доработать алгоритм.
Цитата
Игорь Б написал: Я уникальность обеспечиваю фиксированием момента времени включения скрипта, а не совершения транзакции. А уже дальше, если в скрипте есть сделка, то как обычно, к полученному случайному числу +1.
Не думаю, что у Вас получится в один и тот же момент включить несколько скриптов. os.time() у всех будет разный, а соответственно math.randomseed(os.time()) и ....
Передаётся же строка, господа! А потому пришпилив первыми одним-двумя символами ID скрипта, мы получим гарантированную уникальность при любом их количестве (если гарантирована их уникальность для одного скрипта).
Незнайка написал: Есть идеи, как сделать уникальный trans_id в разных роботах без необходимости задавать свой диапазон (robot_id) внутри каждого робота (или их копий)?
Если робот работает в личной инстанции QUIK то можно взять Process ID из операционной системы, нормализировать по длине, и к нему спереди приклеивать порядковый номер транзакий и т.п. Альтернативно, можно брать адрес его функции main - для разных роботов (из разных файлов) он будет разный.
Цитата
BlaZed написал: В результате чтобы нарушилась уникализация надо одним роботом более 100 раз в секунду транзакцию сделать, что практически невозможно.
Делать ставку на то что маловероятное событие НИКОГДА не произойдёт - плохая тактика. Владимир уже на своем опыте об этом знает.
BlaZed написал: В результате чтобы нарушилась уникализация надо одним роботом более 100 раз в секунду транзакцию сделать, что практически невозможно.
Делать ставку на то что маловероятное событие НИКОГДА не произойдёт - плохая тактика. Владимир уже на своем опыте об этом знает.
Ну надо же соблюдать баланс между идеалом и разумностью. Если у кого-то хотя бы теоретически может быть более 100 транзакций в секунду, то предложенный мной способ, конечно, не подойдет.
Вот только есть ли такие люди? Даже на высокочастотном скальпинге столько не надо. Я вот даже представить не могу кому может не хватить такой уникализации. Вы можете?
BlaZed, Но ведь Артём говорил про теоретическую возможность. У меня скрипт, возможно, никогда не выдавал более 100 транзакций за сутки, но теоретически он способен за один вызов полуторасекундного обработчика послать заявки на покупку или продажу ПО ВСЕМ тикерам, за которыми он следит, а таковых у него сейчас более тысячи. Конечно, вероятность подобного почти равна нулю, но всё же только почти.
Тут суть скорее в том что есть практическая возможность использовать алгоритм который не даёт осечек (просто ID+=1)* а вы используете стохастические и ограниченно-отказоустойчивые, в результате чего со временем происходят ошибки.
*даже выполняя миллион транзакций в секунду, что вчетверо выше пиковой пропускной способности NASDAQ, оверфлов произойдет не ранее чем через ~38,9 миллиардов лет
И по теме (описание интерфейсных функций OS_Quesha): 5.3 Создание последовательности ключей Последовательность ключей это функция, при обращении к которой выдаются значения некото- рого типа, уникальные в некотором контексте их использования. Дополнительным требованием (кроме уникальности значений), в некоторых случаях использования таких функций, может быть необходимость формирования их значений по определенным правилам. В качестве примера использования последовательности можно привести создание идентифи- каторов заявок при их выставлении в QUIKе с помощью функции sendTransaction. 1. Запрос последовательности ключей (number): Cl_LuaGL () Результат функции: number - глобальный ключ системы формата: <Номер запус- ка/перезапуска системы >(старшие, оставшиеся разряды, начиная с 6-го )<Счетчик запросов ключей после запуска/перезапуска системы>(6 десятичных разрядов) Эта функция при обращении из любого потока (функции скрипта), выдает значение отличное от всех ранее ее вы- данных (независимо того, были запуски или перезапуски системы).
Комментариев обсуждения функции cоздания последовательности ключей я насчитал более двадцати. Это одна из самых простых функций из списка API OS_Quesha, оглавление описания которого в документации приводится ниже. 1. Вывод сообщений. 2. Работа со временем. 3. Создание последовательностей ключей. 4. Создание среды функционирования разрабатываемого робота. 5. Взаимодействие потоков. 6. Обеспечение явной синхронизации потоков. 7. Работа с таймерными событиями. 8. Работа с контрольными точками. 9. Работа с фоновыми заданиями. 10. Обеспечение отладки функций и взаимодействия потоков. 11. Разное. Примером простой (классическая задача на рекурсию), но, наверное, полезной функции из раздела 10 является универсальная функция печати переменных dump_str. Она может быть использована в тексте программ для вывода любых переменных (и таблиц произвольной вложенности) Lua. Ниже приводится код функции, которую можно использовать автономно (может быть кому то окажется полезной):
Код
--- Вывод произвольной таблицы в виде таблицы-массива строк ------
------ Параметры: 1) t - таблица (выводятся все вложения до limit); 2) i - строка формирования отступа при выводе вложений (например, " ")
---- 3) limit - уровень вложенности до которого просматривается таблица (если = 0, то все уровни)-----
--- ! Результат: таблица строк: структура со значениями таблицы t (текстовая сортировка по возрастанию индексов таблиц). -----
--- !! Элемент таблицы [1] - заголовок таблицы. Остальные элементы - строковые представления структуры таблицы t
--- с дополнительными служебными описаниями вложенных в t таблиц. -----
function dump_tbl(t, i, limit)
if type(t) ~= "table" then
return nil
end
local tbl = {}; --- для результата ----
tbl[#tbl +1] = "===== Таблица (текстовая сортировка по возрастанию индексов таблиц): " .. tostring(t)
.. " \n ! Количество выводимых уровней вложенности (если = 0, то выводятся все) = " .. limit .. "\n"
if next(t) == nil then --- таблица пустая -------
tbl[#tbl +1] = "Таблица пустая"
return tbl
end
local seen={} -- просмотренные --
local Level =1
-----------
function dump(t,i) ---------
if seen[t] then return end
seen[t]=true
local s={} --- массив хранение имен ключей (строк) для сортировки ---
local ss={} -- массив для хранения самих ключей --
local n=0
local ks=0
for k, v in next,t do
ks = tostring(k)
n=n+1
s[n] = ks
ss[ks] = k
end
table.sort(s)
local tt
for k,v in next,s do
tt=t[ss[v]]
if not seen[tt] then
tbl[#tbl +1] = i .. "[" .. v .. "] (" .. type(tt) .. ") = " .. tostring(tt) .. "\n"
if Level < limit or limit == 0 then
if type(tt) == "table" then
Level = Level +1
tbl[#tbl +1] = i .. "Вложенность: " .. Level .. " === Содержимое таблицы : " .. v .. "\n"
dump(tt, i.."\t")
tbl[#tbl +1] = i .. "Вложенность: " .. Level .. " === Конец таблицы " .. v .. "\n"
Level = Level - 1
end
end
end
end
end
---------------------
dump(t,i)
return (tbl)
end
В диалоге OS_Quesha, в процессе ее работы, функцию dump_str можно вызвать в любой момент для любой глобальной переменной скрипта с тем, чтобы распечатать ее с выдачей в журнал отладки. Например, у меня контекст Lua (переменная _G) выводится (это ~5000 строк) за 20 млсек (по поводу скорости вывода жду комментария Владимира ).
TGB написал: Комментариев обсуждения функции cоздания последовательности ключей я насчитал более двадцати. Это одна из самых простых функций из списка API OS_Quesha
Ставить дополнительную библиотеку только лишь для создания уникальных ключей - не лучшее решение.
Цитата
TGB написал: 1. Запрос последовательности ключей (number): Cl_LuaGL () Результат функции: number - глобальный ключ системы формата: <Номер запус- ка/перезапуска системы >(старшие, оставшиеся разряды, начиная с 6-го )<Счетчик запросов ключей после запуска/перезапуска системы>(6 десятичных разрядов)
<Номер запуска/перезапуска системы > сохраняется в каком-то файле на диске? Тогда такой вариант можно и без библиотеки сделать. Прочитать из файла последнее значение, увеличить на 1:
Код
local LaunchNumber = (file:read("*n") or 0) + 1
Сохранить новое значение в файл. И далее использовать, например:
TGB написал: Примером простой (классическая задача на рекурсию), но, наверное, полезной функции из раздела 10 является универсальная функция печати переменных dump_str.
Преобразование одной таблицы в другую... Сомнительная польза.
Цитата
TGB написал: функцию dump_str можно вызвать в любой момент для любой глобальной переменной скрипта с тем, чтобы распечатать ее с выдачей в журнал отладки.
Может, лучше сразу распечатать таблицу в виде строки, без конвертации в другую таблицу?
В диалоге OS_Quesha, в процессе ее работы, функцию dump_str можно вызвать в любой момент для любой глобальной переменной скрипта с тем, чтобы распечатать ее с выдачей в журнал отладки.
Это довольно распространенный вариант на просторах. Вы попробуйте им вывести Класс или таблицы с перекрестными ссылками.
Незнайка написал: Ставить дополнительную библиотеку только лишь для создания уникальных ключей - не лучшее решение.
Согласен. Но я не предлагаю что-то ставить. Я привел оглавление описания API и одну из простых, но полезных, по моему мнению, для разработчиков функций.
Цитата
Незнайка написал: Может, лучше сразу распечатать таблицу в виде строки, без конвертации в другую таблицу?
У меня используется специальная быстрая функция сборки строки из массива строк и я это делаю в dump_str используя dump_tbl. Дело в том, что цикл вида: <строка1> = <строка1> .. <добавляемая строка> при большом количестве повторений (а я предполагаю что это может быть) в Lua заметно нагружает управление памятью. Вы же можете получать свою строку следующим образом: local str = "" for k,v in next, dump_tbl (<Параметры>) do str = str .. v end или модифицировать код функции dump_tbl.
Цитата
Nikolay написал: Вы попробуйте им вывести Класс или таблицы с перекрестными ссылками.
Функция dump_tbl рекурсивная и в ней раскручиваются все ссылки.
TGB написал: Дело в том, что цикл вида: <строка1> = <строка1> .. <добавляемая строка> при большом количестве повторений (а я предполагаю что это может быть) в Lua заметно нагружает управление памятью.
В чём это выражается?
Цитата
TGB написал: Вы же можете получать свою строку следующим образом: local str = "" for k,v in next, dump_tbl (<Параметры>) do str = str .. v end или модифицировать код функции dump_tbl.
Незнайка написал: И там и там конкатенация строк. В чём профит?
В том как я предложил вам собирать строку профита нет. Профит есть при использовании специальной быстрой C-функции сборки строки из массива строк (тоже из API, но С-пакета, который пришлось бы устанавливать). Если собирать без профита, то при выполнении операции <строка1> = <строка1> .. <добавляемая строка> в Lua всякий раз выполняется отказ от предыдущей памяти <строка1> и запрашивается новая память под новое значение <строка1>. В быстрой C-функции сборки строки на C++ реализована эффективная динамическая строка, в которую последовательно добавляются <добавляемые строки> вообще без описанной мною в предыдущем предложении нагрузки на автоматическое управление памятью.
TGB, А каким боком здесь Владимир? По какому "поводу скорости вывода жду комментария Владимира"? Откуда ему знать?
Но, раз просят, комментирую... вот,глаз зацепился за "table.sort(s)" - у Владимира свой собственный сортир, супер-пупер-эффективный.
А ещё глаз зацепился за "это ~5000 строк" - у Владимира весь скрипт 736 строк - это со всеми комментариями и пустыми строками (37738 байт). А "по поводу скорости" 20 млсек - это очень мало: Владимир оперирует секундами или ещё более медленными интервалами.
s_mike@rambler.ru написал: dump_tbl ({[{"xx","yy"}]=5}, " ", 0)c dump_tbl ({math.huge}, " ", 0) тоже как то не очень.dump_tbl ({"a\0b"}, " ", 0)Торопитесь, TGB ..
Спасибо за нетривиальные примеры для тестирования.
local str = "" for k,v in next, dump_tbl ({ [ {"xx","yy"} ] =5}, " ", 0) do str = str .. v end РЕЗУЛЬТАТЫ теста (в квадратных скобках индексы таблиц) MessageDlg ( 1, 1, "Скрипт", " Результат: \n" .. str) Результат: [table: 0F4ED2F0] (number) = 5 ------- str = "" for k,v in next, dump_tbl ({"a\0b"}, " ", 0) do str = str .. v end MessageDlg ( 1, 1, "Скрипт", " Результат: \n" .. str) Результат: [1] (string) = a MessageDlg ( 1, 1, "Скрипт", " Результат: \n" .. "a\0b") Результат: a --- message ("a\0b") Результат: a ------- str = "" for k,v in next, dump_tbl ({math.huge}, " ", 0) do str = str .. v end MessageDlg ( 1, 1, "Скрипт", " Результат: \n" .. str) Результат: [1] (number) = 1.#INF message (tostring(math.huge)) Результат: 1.#INF ----------------------------------------------------------------------------------------- Я ошибок не нашел. Где они?
в первом примере не раскрыто содержимое таблицы, являющеся ключом. Сериализация это подразумевает. Таблица ключа может содержать вложенные таблицы, которые также должны быть раскрыты.
во втором случае результат явно неверен. "a" и "a\0b" - совершенно разные строки.
в третьем случае 1.#inf не является допустимым числом lua. Это всего лишь нерегламентированное внутреннее представление, которое не может попадать в результат.