Средства разработки многопоточных скриптов в QUIK.

Страницы: Пред. 1 ... 3 4 5 6 7 След.
RSS
Средства разработки многопоточных скриптов в QUIK., OS_Quesha, свидетельство регистрации в Роспатенте № RU 2020612905. Бесплатная для некоммерческого использования.
 
НАДО! Причём не только автору, но и нам! Если автор нас не устраивает, а тема интересная, заводим свою ветку по той же тематике и ведём дискуссию уже там.
 
Цитата
Владимир написал:
НАДО! Причём не только автору, но и нам! Если автор нас не устраивает, а тема интересная, заводим свою ветку по той же тематике и ведём дискуссию уже там.
  С самим собой :smile:
 
Бывает и так.  :smile: Следовательно, ни автор,ни тема никому не интересны.
 
Владимир, не забывайте, что данный форум это не просто общение, но и какое-никакое средство коммуникации с разработчиками терминала.
Задаешь вопрос, ожидаешь получить ответ от них, а не комментарии, что это никому не надо.

На форуме есть ветка https://forum.quik.ru/forum17/ для произвольного общения.
 
Nikolay, Я в курсе.  :smile: Один из самых первых моих постов в этом форуме содержал слова:
Спасибо, Роман! Очень понравился ваш сервис общения с клиентами. Вы ведь сотрудник компании? Передайте руководству мою искреннюю благодарность.

Вот уж что-что, а "произвольное общение" меня никогда не интересовало.
 
Цитата
Артем написал:
Язык отличный и документация исчерпывающая - всё верно.
Добавлю свои «пять копеек».
 Чтобы было понятно, что у меня есть с чем сравнивать, отмечу:  Lua не первый язык, с которым я знаком, и даже не пятый.
 Далее коротко.
1. Lua, по сути, двухуровневый язык: Lua/C. Эта двухуровневость была заложена в проект языка и реализована изначально (Lua тесно интегрирован с C/C++). Таким образом никаких ограничений ни на функиональность, разрабатываемых программ, ни на их эффективность, языком не накладывается.
2. Сам Lua очень компактный, как по исполняемому коду, так и по его описанию, достаточного  для его начального использования. Особенно это заметно на фоне многочисленных монструозных средств разработки программ. Пожалуй, отношение <функциональности  Lua>  к <его компактности> одно из самых высоких среди известных мне языков программирования.
  Для хорошего понимания Lua, в основном, достаточно четкого представления об устройстве ассоциативной таблице, которая используется, в том числе, и для хранения всех переменных самой программы Lua. Переменные всех типов Lua это всего лишь типы полей в таких таблицах. В переводе на другие известные языки: обычные таблицы Lua это динамичный список свойств, а метатаблицы - это методы, связанные с этими свойствами. И это, почти все, что достаточно знать, чтобы хорошо разбираться в остальных деталях Lua (в областях видимости переменных и т.д.). Профессионал, наверное, сможет изучить этот язык, почти в полном объеме, дня за два-три. Для начинающих программировать это язык тоже, наверное, один из самых простых.
  Если делать в программах на Lua проверку типов параметров (а может быть и областей значений) более-менее содержательных функций, то можно повысить и надежность разрабатываемых на Lua программ.
 
TGB, Тут важнее другая особенность: Lua не просто язык, но язык для работы в "многопроцессорной" системе:  скрипт, который просто кусок текста, интерпретируемый Квиком, сам Квик, сервер брокера, к которому обращения идут через провайдера и (в теории) биржа. Ошибки и рассогласования возможны при движении по всей этой цепочке, причём в обе стороны.

1. Сам факт, что "двухуровневость была заложена в проект языка и реализована изначально" уже доказывает, что Lua не есть хороший язык, а эта "интегрированность с C/C++ имеет целый ряд весьма неприятных следствий,из-за которых я и писал с самого начала скрипт на чистейшем Lua, благо ни особая функциональность, ни особая эффективность для задач торговли не требуется.

2. Да, "сам Lua очень компактный" - код моего скрипта (который делает всё, что должен был делать по изначальному замыслу) на данный момент составляет 18744 байта, и вряд ли когда-либо вылезет за 20К. Ну так ведь это же ИНТЕРПРЕТАТОР! Точнее, интерпретируемый текст.

Не знаю, почему эта хрень называется "ассоциативной таблицей", но для меня это однозначно дерево - конструкция действительно удобная, но не как замена, а как дополнение к обычным массивам или таблицам с доступом через индексы, а не имена. Ну, а за динамическую типизацию и за тип integer... далее нецензурно. :smile:

Ну и два сегодняшних подарочка, две новые диагностики, в дополнение к более ранним "счёт депо не найден" теперь получаем и "неверно указан торговый счёт" и даже оглушающее "превышен общий лимит кредитования"! До удобства ли языка при таком поведении всей системы?
 
Цитата
Владимир написал:
сам Квик, сервер брокера, к которому обращения идут через провайдера и (в теории) биржа. Ошибки и рассогласования возможны при движении по всей этой цепочке, причём в обе стороны.
 Все это надо учитывать. А какие претензии к Lua?

Цитата
Владимир написал:
Сам факт, что "двухуровневость была заложена в проект языка и реализована изначально" уже доказывает, что Lua не есть хороший язык, а эта "интегрированность с C/C++ имеет целый ряд весьма неприятных следствий,из-за которых я и писал с самого начала скрипт на чистейшем Lua,
 Вы сами себя опровергаете.
 Вы ни с чем не желаете иметь дело кроме Lua и вполне этим обходитесь (при этом не мало покувыркашись с реализацией диалога на таблицах QUIK).
 Я после того как увидел то, что собой представляет собой архитектура QUIK в части обработки колбеков, а также в части реализации таблиц QUIK (не путать с таблицами Lua) имел возможность, используя второй уровень Lua, потроить то, что считал нужным для себя.
 Все почти счастливы. А вы вы утверждаете, что двухуровневость это недостаток.
После того, как у вас в портфеле появится 1 000 000 акций, вам не надо выбрасывать разработанный вами код, Достаточно будет дополнить его некоторой частью на C, который вам знаком  :smile:
 
TGB, В ЭТОМ у меня никаких претензий к Lua. Но и насчёт "всё это надо учитывать" я не согласен: нет торговли кроме Квика и терминал - Пророк её! Это всё уже НЕ НАШИ проблемы, не скрипта и не языка.

Да, язык дерьмовенький, диалог на таблицах QUIK убогий и сами таблицы глючные. Зато код не зависит ни от версий Квика, ни от версий языка вообще никак! Сам Квик падает, а скрипт - нет. И это дорогого стоит! В этом и заключается недостаток двухуровневости. К тому же, если бы язык был хорош, то кто бы стал переходить "на второй уровень"? Для чего?

Не, после того, как у меня в портфеле появится 1 000 000 акций, мне не надо даже трогать разработанный мною код, он прекрасно справится и с миллионом! Я так ДУМАЮ!(с)  :smile:  
 
Конструктивной частью нашей (во многом, содержательной) дискуссии с Артемом я считаю, для себя, реализацию модифицированного модуля  сереализации Lua-таблиц. Этот модуль создан в соответствии с вариантом решения, который был кратко описан мною в комментарии № 164.  
  Замечу, что мои комментарии в ходе дискуссии с Артемом, особенно в части размеров кода, относились к функциональности, выложенного им модуля. Функциональность модифицированного модуля, а также эффективность выполнения в нем сереализации и восстановления таблиц, иные.
---
  Код модуля выложен в конце данного комментария.  
-----
  В простом варианте восстановления сереализованной таблицы (в том числе и после перезапуска скрипта), когда контекст (определение приведено в описании модуля) ее восстановления не отличается от контекста сереализации, все просто:
     --   Сереализация  таблицы --
    <Строка образа (! в случае отсутствия 3-го параметра)>  = tbl_to_str (<Таблица> [, <Путь файла сохранения образа или вид результата (0 | 1 байт-код или строка-скрипт)> [ ,<Контекст сереализации>]])
 
    ………… !! Здесь может быть и перезапуск скрипта  --

     -- Полное восстановление таблицы (со всеми ее значениями без исключения )   --
    <Таблица)> = str_to_tbl (<Сохраненный где образ - результат функции tbl_to_str > [,<Контекст сереализации>])
------
   Более сложный вариант использования модуля (при различии контекста восстановления таблицы от контекста сереализации) приведен далее, в его описа-нии.
--------------------------------------------
  В описании модуля значения типов function, userdata и thread называются ссылочными значениями.
  Сереализуемая таблица, в описании, обозначена именем <T>.
  Внутренним именем ссылочного значения называется результат функции internal_name (<Cсылочное значение>), определенной в модуле.
  Составное имя имеет вид адреса поля в таблице: <T1>.<T2>…..<Tn>.<Поле таблицы Tn>
  Под контекстом выполнения (сереализации, восстановления) далее описываемых функций понимается список доступных им, в момент их выполнения, ссылочных значений, на которые есть ссылки из <T>.
--
   Описание модуля.
1. Существенных отличий данного модуля, от выложенного Артемом, три:
1) Формирование таблицы ссылочных значений <T> в формате, обеспечивающем, полное восстановление <T> (в том числе, с учетом ее локаль-ного окружения) в контексте ее сереализации из образа, сохраненного в файле (в том числе и после перезапуска скрипта).  Кроме того, обеспечен удобный контроль и коррекция результата восстановления <T> в контексте, отличном от контекста ее сереализации.
2) Результатом сереализации таблицы <T> является Lua-скрипт восстановления этой таблицы (в виде байт-кода или исходного кода Lua), со-держащий в себе две таблицы ссылочных значений (контекста и <T>),
3) На таблице _G (в моем скрипте) время выполнения сереализации в дан-ном модуле в ~1,5 раза меньше, чем в сравниваемом модуле, а время восстановления _G меньше в ~ в восемьнадцать раз (мои конкретные числа данного модуля для _G ~ 8000 элементов:  сереализация ~ 55 млсек., восстановление ~ 2 млсек.). С уменьшением сереализуемой таб-лицы, описанные выше времена, уменьшаются почти линейно.

2. В модуле доступны пять функций:
1) Сереализация таблицы:
tbl_to_str (<T>  [, <Признак выдачи результата в виде байт-кода или строки-скрипта 0|1> | <Путь файла записи строки-скрипта > [ ,<Контекст сереализации: таблица или функция >] ])
 Результат в зависимости от входных параметров: <байт-код восстановления <T> | <Строка-скрипт восстановления <T>> | <Запись строки-скрипта в файл с заданным путем>.

2) Восстановление таблицы:
str_to_tbl (< Байт-код скрипта для восстановления <T>, либо строка-скрипт>[ , <Контекст восстановления: таблица или функция >])
Результаты. Их может быть один или три (если есть висячие ссылочные значения):
1-й - восстановленная таблица с пометкой висячих ссылок,  если такие существуют в виде составных имен в контексте сереализации.
Второй и третий – nil, если висячих ссылок нет или две таблицы:
 -  таблица висячих ссылок с указанием составных имен-адресов в кон-тексте сереализации;
 -  таблица висячих ссылок с указанием составных имен –адресов в <T>.
Эти данные могут быть основой для восстановление  таких ссылок.

3) Формирование служебных таблиц, используемых в функциях tbl_to_str и str_to_tbl:
creating_link_tables (<Контекст выполнения функций tbl_to_str и str_to_tbl > [, <Признак обновления существующего контекста = 1>])
  Первый параметр либо таблица (например, _G), либо пользователь-ская функция создания таблиц контекста (по образцу аналогично тому, как это делается в creating_link_tables). В случае функции, при создании | изменении контекста, вместо  creating_link_tables запускается пользовательская функция. По умолчанию контекстом является _G.
 Результаты функции две таблицы формируемые в ней.

4) Сбор (быстрый) строки из массива строк:
       m_str_to_str_fast ( <Таблица-массив строк> [, <Признак последовательности сбора (false – прямой; true – обратный) >] ).

5) Печать любой таблицы Lua в виде удобном для анализа, с указанием уровней вложенности всех ее элементов:
dump_tbl (<Таблица>, <Символ отступов для выделения вложенности эле-ментов таблицы>, <Уровень раскрываемых вложенностей таблицы (если 0, то показывается все > [, <Вид выдачи результата: false – таблица (по умол-чанию); true - строка> [, < Таблица имен элементов (задаваемых в ключах) , не разворачиваемых далее >]]).
----  
В квадратных скобках при описании всех функций указаны необязательные параметры.

3. При сереализации <T> ее ссылочные значения не сохраняются, но при восстановлении <T>,  ссылки на ее ссылочные значения, разрешаются (устанавливают-ся на значения) в контексте ее восстановления. Если контекст, в момент восстановления <T>, такой  же (в части всех ее ссылочных значений), как и в момент ее сереализации, то ничего кроме запуска функции str_to_tbl с единственным параметром-результатом, полученным из функции tbl_to_str не требуется;   в этом случае таблица <T>  будет восстановлена полностью (со всеми ее значениями, включая ссылочные).
  При отличии контекста восстановления от контекста сереализации таблицы в момент ее восстановления, некоторые ссылки могут оказаться «висячими».  Для возможности восстановления висячих ссылок функция str_to_tbl выдает дополнительно к восстановленной <T> c указанием в ней висячих ссылок,  две таблицы описания таких ссылок в удобном для анализа виде.

4. В функции str_to_tbl выполняется автоматический контроль разрешимости ссылок <T> на ее ссылочные значения.  Выполняемый контроль частичный, в том смысле, что если он не проходит, то это значит, что контекст восстановления <T> точно отличен от контекста ее сереализации.  Если же этот контроль проходит, то это означает, что имеется всего лишь полное совпадение сформированных имен ссылочных значений <T>, с именами контекста ее восстановления. При этом может оказаться (! только при отличии контекста восстановления <T> от контекста сереализации), что какая то часть восстановленных ссылочных значений не валидна (восстановленное значение отличается от сереализованного). Вероятность появления невалидности значений, скорее всего, будет очень малой, но не 0. Это надо учитывать и, для случая отличия контекста восстановления от контекста сереализации, желательно выполнять дополнительный контроль а, при необходимости и исправление.
----------
    Модуль можно использовать свободно, а при распространении, желательна ссылка на меня. Сообщения об обнаруженных ошибках, замечания и вопросы будут мне интересны.
---
   Одним из вариантов использования данного модуля может быть реализация контрольной точки, обеспечивающей продолжение выполнения любой цикличе-ской функции (аналога функции main в QLua) после ее перезапуска (по любой причине). При этом, для эффективности контрольной точки (уменьшения сохра-няемых данных) а также защищенности данных функции, можно реализовывать (по крайней мере, начиная с версии 5.3), с помощью _ENV, дополнительно к ее локальным переменным, собственное окружение функции, хранящее только ис-пользуемые в ней, ее сереализуемые значения. Такой вариант реализован мною в OS_Quesha для некоторых ее системных циклических функций.
 
  Код модуля:
Код
--  Модуль сериализации таблиц. Автор TGB ---
---------------------------
--- Быстрая сборка строки из массива строк ----
--  Не обязательный параметр pr = false - строка собирается в прямом порядке (от начала массива к концу); true - строка собирается в обратном порядке --
local function m_str_to_str_fast ( m_str , pr)
  if type (m_str) ~= 'table' then  return  nil,  ' ! Ошибка. Первый параметр m_str_to_str_fast не таблица ***' end
  local const_mod = 10,   m_str_tm
  local mod,  N , NN
  local N_mod, i_mod 
  ----
  if pr then
     m_str_tm = {}
    NN = #m_str
    for i =  NN, 1, -1   do   m_str_tm [NN - i +1] = m_str [i]   end
    m_str = m_str_tm;        m_str_tm = {}
  end
  while 1 do
       m_str_tm = {}      
       mod,  N,  NN  =  #m_str % const_mod,   math.floor (#m_str / const_mod),    #m_str
            N_mod = N * const_mod
            for i = 1, N do
              i_mod = (i -1)*const_mod
                 m_str_tm [i] = m_str [ i_mod + 1] .. m_str[ i_mod + 2] .. m_str [ i_mod + 3] .. m_str [ i_mod + 4] .. m_str [ i_mod + 5] 
                              .. m_str [ i_mod + 6]  .. m_str [ i_mod + 7] .. m_str [ i_mod + 8] .. m_str [ i_mod + 9] .. m_str [ i_mod + const_mod]
           end
            if mod > 0 then
               N = N + 1;    m_str_tm [N]  = ''
               for i = 1, mod   do  m_str_tm [N] =  m_str_tm [N] .. m_str [N_mod + i]  end
            end
      ----
       if  #m_str_tm  > 1 then  
            m_str = m_str_tm
        else return m_str_tm [1]
        end
  end
end
----------------------------------

----------------------------------
---             Вывод  произвольной таблицы  в виде таблицы-массива строк (либо в виде строки)         ------
------  Параметры: 
--      1) t  -  таблица (выводятся все вложения до limit);  
--      2) i  -  строка формирования отступа при выводе вложений (например, '  ')  
----    3) limit - уровень вложенности до которого просматривается таблица (если = 0, то все уровни)-----
----    4) (не обязательный) <Вид выдачи резкльтата: false – таблица (по умол-чанию); true - строка>
----    5) (не обязательный) <Таблица имен элементов (задаваемых в ключах) , не разворачиваемых далее >
--- ! Результат: таблица строк:   структура со значениями таблицы t  (текстовая сортировка по возрастанию индексов таблиц) либо строка, 
---                                                   в зависимости от параметра pr-----
---  !!  Элемент таблицы [1] - заголовок таблицы. Остальные элементы - строковые представления  структуры таблицы t 
---       с дополнительными служебными описаниями вложенных в t таблиц.   
local function dump_tbl (t, i, limit, pr, list)
   if type(t) ~= 'table' then
       if pr   then    return  ' Первый параметр t не таблица.  Результат: ' .. tostring(t) end
       return nil,  '! Ошибка. Первый параметр t не таблица'
   end  
   list = list or {} 
   if type(list) ~= 'table' then
         return nil,  '! Ошибка. Параметр list не таблица'
   end 

   limit = limit or 0
   local tbl = {};  ---   для результата  ----
   tbl[#tbl +1]  = '=====    Таблица (текстовая сортировка по возрастанию индексов таблиц): ' .. tostring(t) 
                      .. '  \n                                      ! Количество выводимых уровней вложенности (если = 0, то выводятся все) =  ' .. limit .. '\n' 
   local seen={}    --  просмотренные --
   local Level = 0
    ------------------------------------------
   local function dump(t,i, nm)      -----
        nm = nm or 'T'
       if seen [t] then    
          return seen [t] 
       end   
        ------      
        seen [t] = nm    --- !
      local  t_v,  t_k, nm_tm
      Level = Level +1  --- Уровень вложенности таблицы ----
      
      ---  Обработка метатаблицы   ----
      local  mt   =  debug.getmetatable ( t ) 
      if  mt  then                       
          nm_tm = seen[mt] 
            if  nm_tm  then 
               tbl[#tbl +1]  =  i .. 'Для таблицы ' ..  nm .. '   cсылка на существующую метатаблицу   ->  ' .. nm_tm .. '\n'
            else   
               nm_tm = tostring(mt)                  
              tbl[#tbl +1]  =  i .. 'Вложенность: ' .. Level .. '  === Содержимое метатаблицы ### :  '  .. nm_tm .. '\n'
             dump(mt, i..'\t', nm_tm)
               tbl[#tbl +1]  =  i .. 'Вложенность: ' .. Level .. '  === Конец  метатаблицы  ## ' .. nm_tm .. '\n'   
         end   
        end   
      
      if next (t) == nil then  ---- Таблица пустая ---
          tbl[#tbl +1]  =  i .. 'Вложенность: ' .. Level .. '  Таблица:   '  ..  nm .. '  пустая ###  '.. '\n'  
           Level = Level - 1 
         return ''   
      end
      
        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)

        for k,v in ipairs(s) do   --- 
          t_k = ss [v]   -- ключ записи в t
          t_v=t [t_k]   -- значение записи в t
        
         if Level < limit or limit == 0 then
                if type(t_k) ==  'table' then                                 --- Обработка ключа-таблицы ---
                   nm_tm = seen[t_k]
                       if  nm_tm  then 
                           tbl[#tbl +1]  =  i .. '[ ' ..  tostring(t_k) .. ' -  cсылка на существующую таблицу-ключ  ->  ' .. nm_tm .. ']' .. '\n'
                       else                  
                     tbl[#tbl +1]  =  i .. 'Вложенность: ' .. Level .. '  === Содержимое ключа-таблица $$ :  '  .. v .. '\n'  
                     dump(t_k, i..'\t', tostring(t_k)) 
                      tbl[#tbl +1]  =  i .. 'Вложенность: ' .. Level .. '  === Конец  ключа-таблицы  $$ ' .. v .. '\n'   
                  end     
                end   

           if list [v] then
              if type(t_v) == 'table' then
                   tbl[#tbl +1]  =  i .. '[' .. v .. ']   (' .. type(t_v) .. ') = ' .. tostring(t_v) .. '  |  Терминальная таблица (в печати задано далее не разворачивать) ### \n'
             else   
                  tbl[#tbl +1]  =  i .. '[' .. v .. ']   (' .. type(t_v) .. ') = ' .. tostring(t_v) .. '\n'
             end   
           else          
                  tbl[#tbl +1]  =  i .. '[' .. v .. ']   (' .. type(t_v) .. ') = ' .. tostring(t_v) .. '\n'
                  if type(t_v) == 'table' then   ---  Обработка таблицы   ----                                          
                 nm_tm = seen [ t_v]  
                      if  nm_tm  then 
                          tbl[#tbl +1]  =  i .. '[' .. v .. ']     ссылка на существующую таблицу  ->  ' .. nm_tm .. '\n'
                      else                                                   
                        tbl[#tbl +1]  =  i .. 'Вложенность: ' .. Level .. '  === Содержимое таблицы :  '  .. v .. '\n'
                   dump(t_v, i..'\t', tostring(t_k))
                       tbl[#tbl +1]  =  i .. 'Вложенность: ' .. Level .. '  === Конец таблицы   ' .. v .. '\n'
                      end                  
                  end 
              end   
          end
        end
      Level = Level - 1
      return ''
    end
   --------------
    dump(t,i, tostring(t))  
    if pr then               --- Выдача результата в виде строки
        return  m_str_to_str_fast ( tbl)  
    else   return  tbl     --- Выдача результата в виде массива строк
    end    
end

-------------------------------- Общие данные модуля -----------------------------------------
---  1. Для выделения строк используется скобки [[     ]] и поэтому внутри них не надо никаких преобразований (типа замены \ на \\ и т.д).
--   2. В выдаваемых стоках для удобства анализа, места, на которые надо обращать внимание в первую очередь выделены символом ###.
----
local aliases_cont = { }      ---   [ <Внутреннее имя ссылочного значения> ] = <Внешнее имя ссылочного значения в контексте>
local aliases_v_cont = { }   ---   [ <Внешнее имя ссылочного значения в контексте> ] = <Ссылочное значение в контексте>
local wo_creator      -- Призак где сформирована таблицы 
local tbl_cont = _G  --- Контекст по умолчанию ---
local context_tbl = 'CONT'  -- Имя, присвоенное контексту
-----
----- Формирование внутренних имен --
local function internal_name ( s )   
    return  tostring ( s ):gsub ( ': ', '' )
end

----------------------------------------------
--  Параметры 
--   1) 1-й параметр либо таблица, либо пользовательская функция соз-дания таблиц контекста (по образцу аналогично тому, 
--   как это делается в creating_link_tables). В случае функции, при создании, изменении контек-стэтом вместо  creating_link_tables 
--    запускается пользовательская функ-ция.
--   2)  необязательный, если 1, то принудительное обновление таблиц формируемых в ней
--  Результаты : две таблицы формируемые в ней.
---
local function creating_link_tables (context, pr)
  if type(context) == 'function' then
      wo_creator = 'no creating_link_tables' 
     local cont, v_cont    =    context (pr)   --- context  должен выдавать два результата ---
     if cont  then   aliases_cont, aliases_v_cont = cont, v_cont  end
     return aliases_cont, aliases_v_cont 
  end
  ------
  if pr  then   aliases_cont, aliases_v_cont = {},  {}   end   -- Обновление общих данных ---
  if  next (aliases_cont) ~= nil  and  not pr    then   return    end    ----  
  if type(context) ~= 'table' then context = tbl_cont  end
  ----
  wo_creator = 'creating_link_tables'
  local path  =   '###: ' .. context_tbl
  ----------------------------
  local function cr_link_tables (item, path, seen)   
    seen  =   seen or { }
   path  =   path or context_tbl
   local mt
    if item == nil or seen [ item ] ~= nil then
        return
    elseif  type ( item ) == 'table' then
        seen [ item ] = true 
      --  Обработка метатаблицы (если есть в item)---
       mt = debug.getmetatable ( item )
       if type ( mt ) == 'table' then  cr_link_tables (mt, path .. '.' .. '.metatable###', seen ) end
      ---
      local path_tm, kl_tm, k_tm
        for k, v in pairs ( item ) do
            if type ( v ) == 'table' then   ---- таблица-значение --
             cr_link_tables (v, path .. '.' ..  tostring ( k ), seen )
         else   
             if  not (type(v) == 'number' or type(v) == 'boolean' or type(v) == 'string') then
              if  type(k) == 'string' then   kl_tm = '.' ..  tostring ( k ) else  kl_tm = '[' ..  tostring ( k ) .. '] '  end
              path_tm = path .. kl_tm 
              k_tm = internal_name (v)
              if not aliases_cont [k_tm]  then   aliases_cont [k_tm] = path_tm   end      --- ### ?? возможна перезапись   ---
                  aliases_v_cont [ path_tm ] = v              
               end
            end
         ----
         if type ( k) == 'table' then   ---- таблица-ключ --
             cr_link_tables (k, path ..'.' .. tostring ( k ), seen )
         else   
             if  not (type(k) == 'number' or type(k) == 'boolean' or type(k) == 'string') then
              if  type(k) == 'string' then   kl_tm = '.' ..  tostring ( k ) else  kl_tm = '[' ..  tostring ( k ) .. '] '  end
              path_tm =  '### ключ: ' .. path .. kl_tm
              k_tm = internal_name (k)
              if  not aliases_cont [k_tm]  then   aliases_cont [k_tm] = path_tm   end      --- ### ?? возможна перезапись   ---
                  aliases_v_cont [ path_tm] = k              
               end
            end
        end
    end
  end
 
  cr_link_tables (context, path)
--  MessageDb ( 1, 1, 'Скрипт', ' Финальные проверки. creating_link_tables - aliases_v_cont :  \n' .. dump_str (  aliases_v_cont , ' ', 0))
---[[
    -- Обработка внешних локальных ссылочных данных контекста ---
   local level = 2, ii,  name, value 
   local  k_tm,   path_tm
   while 1 do
        if  debug.getinfo (level, 'n') then
           ii = 1
           while 1 do
            name, value = debug.getlocal(level, ii)
            if name then
              if  not ( type(value) == 'table' or  type(value) == 'number' or type(value) == 'boolean' or type(value) == 'string') then
                  k_tm = internal_name ( value)
                 path_tm = '###: LOC.' ..  tostring (level) .. '.' ..  tostring (ii) .. '.' .. name
                     if not aliases_cont [k_tm]   then   aliases_cont [k_tm] = path_tm    end      --- ### ?? возможна перезапись   ---
 --                   aliases_cont [k_tm] = path_tm
                      aliases_v_cont [ path_tm ] = value
              end
                else
                 break               
            end
            ii =  ii  + 1
         end
       else
          break
       end
       level = level + 1
   end
   
   ---------------------------- 
---]]
  return aliases_cont, aliases_v_cont 
end
------------------------------------------------------------
--  Функция создает байт-код либо строку-скрипт Lua, при запуске которого восстанавливается таблица t. 
--  В эту же строку в конец добавляется две таблицы ссылочных значений 
----  Параметры:
--    1.  t  - сереализуемая таблица 
--    2. ph_f - (не обязательный)  путь файл сброса строки-скрипта либо признак (0 | 1) выдачи образа в виде (байт-кода | строки - скрипта)
--    3. context  - - (не обязательный) контекст
--   Результат в зависимости от входных параметров: <Функция Lua > (один тараметр)  | <Строка-скрипт> (второй параметр = 1) 
--                                                                                  | <Запись строки-скрипта в файл> (второй параметр строка путь к файлу)
local function tbl_to_str ( t, ph_f, context) 
  ----Контроль параметров ---
  if type ( t ) ~= 'table' then  
      return nil,  '!! Ошибка. Второй параметр не таблица.'  
  end
  ph_f = ph_f or 0
  local f_t 
  if  type(ph_f) == 'string'  then
     f_t = io.open( ph_f, 'w')                                                      
    if    type(f_t ) ~= 'userdata'   then   return nil,  '!! Ошибка при открытии файла'  end
  end

  creating_link_tables (context) 
  ------
  local  name_alias = 'alias'  --- для формирования команд с учетом alias ---- 
  local env_t  =  context_tbl
  local env =  env_t .. '.'
  local path =  '###: TBL'
  local t_str = {}   --- для сбора строк   
  ---
  local name_t, context_t = {}, {}
  
  -----------------------------------------
  local function tbl_str ( t, path, seen )
    seen = seen or { }
    if seen [ t ]  then  
      return   false,   env .. internal_name ( t ) 
   else   seen [ t ] = 0 end         
   -------
    local  n_t,  mt   =   env .. internal_name ( t ),   debug.getmetatable ( t ) 
   t_str [ #t_str + 1 ] = n_t .. ' =  {}                                    --- создание таблицы: ' .. n_t .. ' -- \n'  
   local n_tt,  n_kt,  n_vt , st, nm_t, path_t

    for k, v in pairs ( t ) do    
       if  (type(v) == 'number' or type(v) == 'boolean' or type(v) == 'string') then  -- Простое значение --
          if  type(v) == 'string'  then
               n_vt = '[[' ..  v  .. ']]' 
          else    n_vt = tostring (v)
          end 
      elseif type ( v ) == 'table' then  ---  Таблица-значение  --
         n_vt = internal_name (k)
         t_str[ #t_str + 1 ] =    ' --- ' .. n_vt .. ' - значение-таблица  (начало) @  \n'
         st,  n_vt = tbl_str ( v, path .. '.' .. n_vt, seen )                      
         if not st  then t_str [ #t_str + 1 ] = ' --  Таблица ' ..  n_vt .. ' была создана ранее ----\n ' end
         t_str[ #t_str + 1 ] =     ' --- ' .. n_vt .. ' - [' .. internal_name (v)  .. '] значение-таблица (конец) @  \n' 
      else   --- Ссылочное значение ---
          nm_t = internal_name (v)
         path_t = path .. '.' .. internal_name (k) 
         context_t [nm_t]  = aliases_cont [nm_t]
            if    name_t [nm_t]  then      
                name_t [nm_t]  = name_t [nm_t] .. ' | ' ..  path_t 
            else    name_t [nm_t]  =  path_t   
            end         
          n_vt = name_alias .. '[ [[' .. nm_t .. ']] ]' or '### err'  
      end
      
      if  (type(k) == 'number' or type(k) == 'boolean' or type(k) == 'string') then  -- Простое значение --
          if  type(k) == 'string'  then
               n_kt = '[[' ..  k  .. ']]' 
          else    n_kt = tostring (k)
          end 
      elseif type ( k ) == 'table' then  ---  Таблица-ключ  ---
         n_kt = internal_name (k)
         t_str[ #t_str + 1 ] =  ' --- ' .. n_kt .. ' - ключ-таблица (начало) @  \n' 
         st,  n_kt =  tbl_str ( k, path .. '.' .. n_kt, seen )  --- Создание таблицы ключа и ее 'скобок' ----
         if not st  then t_str[ #t_str + 1 ] = ' --  Таблица ' ..  internal_name ( k ) .. ' была создана ранее ----\n ' end
         t_str[ #t_str + 1 ] =  ' --- ' ..  n_kt .. ' - [' .. internal_name (k) .. '] ключ таблица (конец) @  \n'      --- 
      else   --- Ссылочное значение  ключа ---
          nm_t = internal_name (k)
         path_t = path .. '.' .. nm_t 
          context_t [nm_t]  = aliases_cont [nm_t]
         name_t [nm_t]  =  path .. '.' .. nm_t  .. '.ключ###'    
         if    name_t [nm_t]  then      
                name_t [nm_t]  = name_t [nm_t] .. ' | ' ..  path_t 
            else    name_t [nm_t]  =  path_t   
            end   
          n_kt = name_alias .. '[ [[' .. nm_t .. ']] ]' or '### err'  
      end
      
      n_tt =  env .. internal_name ( t )
      t_str[ #t_str + 1 ] =  n_tt .. ' [ ' ..  n_kt  .. ' ]  = ' .. n_vt  ..  ' \n'           
    end
   if  mt  then    --  создание  и подключение метатаблицы в конце прохода по таблице с тем, чтобы она не мешала заполнять таблицу. Иначе пришлось бы  использовать rawset  ---
       t_str[ #t_str + 1 ] =  '               ---   Создание метатаблицы   --- \n'
      st,  mt = tbl_str ( mt, path .. '.' .. internal_name (mt), seen )
      if not st  then  t_str[ #t_str + 1 ] = '--               Метатаблица ' ..  mt  .. ' была создана ранее ----\n ' end
      t_str[ #t_str + 1 ] =   'debug.setmetatable ( ' ..  n_t .. ', ' ..  mt .. ' )  ---  подключение метатаблицы ' .. mt .. '   --- \n'    
   end
    return  true,  n_t    --- 1 - й результат - признак  создания таблицы
  end
  ---------------------
  tbl_str (t, path) 
  ---  Формирование фрагментов скрипта  -----
  local scr1 = 'local '..  name_alias .. ' =  {...};   ' ..  name_alias .. ' = ' .. name_alias .. ' [1] ;   local ' .. env_t .. ' = {}  \n' 
                .. '\n  if type(' .. name_alias .. ') == "table" then \n'
  local scr2 = '\n  return ' .. t_str[1]: match ( '(%S*)') ..  '\n else \n---  Две таблицы внутренних имен ссылочных значений :    \n ' 
                     .. '  -- 1)  name_cont  [<Внутреннее имя ссылочного значения  >]  = ###: <Составное имя значения в контексте сереализации таблицы> \n'
                     .. '   -- 2)  name_t     [<Внутреннее имя ссылочного значения  >]  = ###: <Список составных имен таблицы, ссылающиеся на значение > \n'
                .. '---                          !   Составные имена таблицы (если их неколько)  разделены символом | . \n'
 
  local scr3 = '\n  local  name_cont = { '
  local scr4= '\n  local  name_t= { '                          
  local scr5 = '\n} '
  local scr6 = '\n  return  name_cont, name_t  end \n '
  ----------------------------
  if  type(f_t ) == 'userdata'  then   --- Запись строки-скрипта в файл ----
    f_t: write (scr1) 
    for i = 1, #t_str do f_t:write (t_str[i]) end
    f_t: write (scr2) 
    f_t:write (scr3) 
    for k, v in pairs ( context_t ) do  f_t:write (  '\n  [ [[' .. k .. ']] ] = [[' .. v ..']],' )  end
    f_t:write (scr5)
    f_t:write (scr4) 
    for k, v in pairs ( name_t ) do  f_t:write (  '\n  [ [[' .. k .. ']] ] = [[' .. v ..']],' )  end
    f_t:write (scr5)
    f_t:write (scr6)
    f_t:close()
     return    
  else   ----------------------
     local s_a = {}  --- для сбора строк  ----
    ----
     local s = scr1 .. m_str_to_str_fast ( t_str)
    s_a[ #s_a + 1 ] = scr2
     s_a[ #s_a + 1 ] = scr3    
     for k, v in pairs ( context_t ) do   s_a[ #s_a + 1 ] =  '\n  [ [[' .. k .. ']] ] = [[' .. v ..']],' end
     s_a[ #s_a + 1 ] = scr5 
    s_a[ #s_a + 1 ] = scr4    
     for k, v in pairs ( name_t ) do   s_a[ #s_a + 1 ] =   '\n  [ [[' .. k .. ']] ] = [[' .. v ..']],' end
     s_a[ #s_a + 1 ] = scr5 
    s_a[ #s_a + 1 ] = scr6
    s_a = m_str_to_str_fast ( s_a)  --  массив строк -> строка
     -----
     s =  s .. s_a  
    if ph_f == 1 then 
       return s   --- Строка-скрипт ---
    else        
       return load ( s )  -- !!!  байт-код скрипта (два результата) ---
    end 
  end
  ------
end
----------------------------------------------------------------------
---              str_to_tbl (<Байт-код скрипта для восстановления <T>, либо строка-скрипт)>[, <Контекст>] )
---  Результаты. Их может быть один или три (если есть висячие ссылочные значения):
--  1-й - восстановленная таблица с gjvtnrjq висячих ссылок,  если такие существуют в виде составных имен в контексте сереализации.
--  Второй и третий – nil, если висячих ссылок нет или две таблицы:
--                  -  таблица висячих ссылок с указанием составных имен-адресов в кон-тексте сереализации;
--                  -  таблица висячих ссылок с указанием составных имен –адресов в <T>. 
--                В таблицах висячих ссылок есть данные, облегчающие восстановление  этих ссылок.-
------
local function str_to_tbl (str_fun, context)
--MessageDb ( 2, 0, 'Скрипт', ' str_fun str_fun: \n' .. dump_str ( str_fun , ' ', 0))
    if type (str_fun) ~= 'string' and type (str_fun) ~= 'function' then
       return nil,  '! Ошибка во 2-м параметре ф-ции str_to_tb  (он должен быть типа string или function )'
   end
   
    local err 
   if type (str_fun) == 'string' then   
       str_fun , err = load ( str_fun );   if  err ~= nil  then   return  nil, err  end 
   end  
    ---------   
    local cont_t,  tbl_t    =   str_fun ()   
   creating_link_tables ( context ) 
   
   ---  Проверка  существования ссылочных значений таблицы -----
    local cont_err,  t_err  =   {}, {}   
    local N_err = 0 
   local v_tm
   --- Первый этап разрешения ссылок ---
   for k, v in pairs ( cont_t ) do
        v_tm = aliases_v_cont [ v]   
        if v_tm then   --- есть ссылочное значение ---
            cont_t [k] =  v_tm
       else 
          N_err = N_err + 1 
          cont_err [ k] =  v
         t_err [ k] =  tbl_t [k]
       end
   end 
   --- Второй этап разрешения ссылок ---
   if N_err > 0 then
       local cont_err_tm = cont_err 
       for k, v in pairs ( cont_err_tm) do
           local  i_mt = # v
         local  v_tm,  yes 
         for i =  i_mt , 1 do  if  v: sub(i, i) == ','   then  i_mt = i;   break   end   end
              if    i_mt <=  # v   then  
                  for i =  i_mt  - 1 , 1 do  if  v: sub(i, i) == ','   then  i_mt = i;   break   end   end   
            i_mt = i_mt + 1
               v_tm =  v: sub(i_mt)
            yes = nil
            for k_k, v_v in pairs ( aliases_v_cont ) do   --- 
                    if    k_k: find( v_tm, i_mt)    then 
                    cont_t [k] =  v_v; yes = 1 break 
               end
            end
                if    yes then 
                    N_err = N_err -1
                     cont_err [ k] =  nil
                  t_err [ k] =  nil   
                end                
         end
      end   
   end
   -----
   if N_err > 0 then
       return  str_fun (cont_t), cont_err, t_err
   else
        return  str_fun (cont_t)
   end
end
-----
 return { tbl_to_str = tbl_to_str, str_to_tbl = str_to_tbl,  creating_link_tables = creating_link_tables,   dump_tbl = dump_tbl ,   m_str_to_str_fast = m_str_to_str_fast }  ---

 
Увидел ошибку:
Цитата
TGB написал:
if Level < limit or limit == 0 then
 Исправление:
if Level < (limit +2) or limit == 0 then
 
Цитата
TGB написал:
4) Сбор (быстрый) строки из массива строк:
       m_str_to_str_fast
Для этих целей table.concat есть.
 
Цитата
Незнайка написал:
Для этих целей table.concat есть.
  Замечание верное. Спасибо.
  Я не знал, что это работает быстро.
 
Инструкцию не читай @ велосипед изобретай. Классика.
 
TGB, Я когда-то занимался чем-то похожим для баз данных, только это дело называлась у меня не "сериализация таблиц", а "транспортный формат данных" ( в общем случае, графовых, а не [только] табличных). Алгоритмически это перевод структурированных данных в общий поток с добавлением необходимых метаданных (перевод информации в данные) и наоборот, перевод данных в информацию. И в том, и в другом случае файловые операции здесь ни при чём - они работают с байтовыми массивами и могут быть вынесены вовне алгоритма преобразования.

Если я правильно понимаю ("результатом сериализации таблицы является Lua-скрипт восстановления этой таблицы"), то здесь имеет место что-то вроде "самораспаковывающегося архива". Решение, несомненно, имеет право на жизнь, хотя я предпочитаю иметь два внешних модуля: упаковщик и распаковщик - это упрощает структуру и уменьшает объём данных "в транспортном формате".

Что такое "ссылочные значения" я не понимаю: на мой взгляд, это точно такие же данные, которые интерпретируются исполнительным механизмом как ссылки (в реляционной терминологии как ключи). То есть они НИЧЕМ не отличаются от любых других данных. По крайней мере, для распаковщика - для различных приложений контроль целостности может быть намного более сложным - и битые ссылки, и висячие элементы (на которые никто не ссылается), и малозаметные вроде как разные ссылки на разные элементы, у которых идентичное содержимое, и чёрта лысого там только не может быть.

Lua-таблицы это, ваще-то, деревья. По крайней мере, у меня при запуске входной файл распаковывается именно в дерево, а при выходе "упаковывается взад". Даже хуже: частично это дерево инициализируется значениями вовсе не из входного файла, а по выходу далеко не всё сбрасывается на диск.
 
Цитата
TGB написал:
Дело в том, что цикл вида:    =   ..   при большом количестве повторений (а я предполагаю что это может быть) в Lua заметно нагружает управление памятью.
Ваши слова заставили задуматься.
Что такое "нагружает управление памятью" я не понял. Но убедился, что при большом количестве склеиваемых строк (от нескольких десятков и выше) выгоднее (в плане скорости) все строки загнать в таблицу, а затем склеить в одну с помощью table.concat. При огромном количестве строк (более 100) скорость склейки в цикле существенно падает (нелинейно).
Правда, не знаю, для каких практических задач может потребоваться склейка огромного количества строк. Например, для сделок используется ~73 параметров, и запись в одну строку из массива строк с помощью table.concat всего лишь процентов на 10% быстрее, чем в цикле.


Цитата
TGB написал:
1) Сереализация таблицы:
tbl_to_str

Код
tbl_to_str(getItem('trades', 0), 'test.txt')
На выходе вместо Lua-таблицы получается какая-то нечитаемая "каша".
Странный выбор... или у нас разное понимание понятия "сереализация". Чем обусловлен выбор такого формата? Он ведь труден для восприятия.

Цитата
Нормальные герои всегда идут в обход
 
Цитата
Артем написал:
Инструкцию не читай @ велосипед изобретай. Классика.
  Не согласен, как говорили в армии: "Хочешь выжить. Учи матчасть!" :smile:
 
Цитата
Незнайка написал:
Правда, не знаю, для каких практических задач может потребоваться склейка огромного количества строк.
  Когда вы занимаетесь своей конкретной задачей, вам действительно, решать задачу склейки огромного количества строк может быть никогда не придется. Но если вы разрабатываете программный инструмент для достаточно широкого круга пользователей, вам придется учесть, что у кого то такая задача может возникнуть. Поэтому у меня (где то это уже отмечалось) в системе есть специальная C-функция сбора строки в один проход практически без нагрузки на управление автоматической памятью Lua. Чтобы использовать эту функцию непосредственно в выложенном мною модуле, пришлось бы подключать мой C-пакет.

Цитата
Незнайка написал:
На выходе вместо Lua-таблицы получается какая-то нечитаемая "каша". Странный выбор... или у нас разное понимание понятия "сереализация". Чем обусловлен выбор такого формата? Он ведь труден для восприятия.
  При сереализации не стоит задача получить строку в удобно читаемом формате.     Для этого есть функция dump_tbl, где выделяются все отступы и т.д.
Для  задачи сереализации достаточно того, чтобы результат str_to_tbl (<строка-результат из функции tbl_to_str (<Таблица>....) был <Таблица>.
 В принципе, не очень сложно, так модифицировать, выложенный мною модуль, чтобы формат сереализованной таблицы был в виде
 {  
      [] = {
                ........
              }
  }
 но это уже не принципиально и я не вижу смысла в том, чтобы этим заморачивться. Строка-результат сереализации предназначена не для изучения ее пользователем, а для подачи в функцию восстановления таблицы.
 
Об оптимизации синхронизации в QLua.
   Не затрагивая существующей архитектуры обработки колбеков в QUIK, можно оптимизировать синхронизацию многопоточности QLua.
   Дело в том, что при синхронизации по умолчанию, как это, похоже, реализовано в существующей QLua, все вызовы C-функций имеют следующий общий вид:
 unlock ….;
<Вызов C-функции>;
 lock ……;
  В операциях unlock и lock возможны преключения потоков. То есть, это ресурсоемкие операции.  Если вызываемая C-функция выполняется быстро, как напри-мер, многие математические функции, то при существующей синхронизации, коэффициент полезного использования времени ЦП может быть очень низким :
 <Время выполнения C-функция > / (< Время выполнения unlock >  + < Время вы-полнения  lock >).
 Понятно, что в циклах QLua с обращением к коротким C-функциям QLua занимается в основном синхронизацией.
 Идея оптимизации состоит в том, чтобы у пользователя была динамическая возможность задания/отмены C-функций, которые вызываются без выше описанной синхронизации (ввести особый список). Сделать эффективную  реализацию выше описанного несложно.
  Чтобы гарантировать обязательную «щель» для запуска колбеков, из списка допустимых C-функций, описанных в предыдущем абзаце операций, имеет смысл исключить sleep, а возможно, и еще какие-то функции обеспечения  задержек по времени и файловые операции.
  Существенным положительным моментом описанной оптимизации является то, что она никак не затрагивает тех пользователей, которые не будут ее использовать. При ее применении, коэффициент полезного использования времени ЦП:
1) для функций из особого списка: <Время выполнения C-функция > / < Время анализа особого списка>  
2) для обычных функций: <Время выполнения C-функция > / (< Время анализа особого списка> + < Время выполнения unlock >  + < Время выполнения  lock> ).
   При качественной реализации оптимизации можно добиться того, чтобы < Время анализа особого списка> было существенно меньше, чем (< Время выполнения unlock >  + < Время выполнения  lock>).
 
Цитата
Владимир написал:
Что такое "нагружает управление памятью" я не понял.

 Попробую объяснить.
 Дело в том, что при программировании на Lua вам совсем не надо управлять памятью (ее запросом/возвратом, контролем за всем этим - большой геморрой при разработке программ). В Lua это делается автоматически ("под капотом"). Тем не менее это все делается за счет вычислительных ресурсов пользователя (время ЦП, память и т.д.).
 Существуют ситуации, в которых вроде бы на безобидных операциях в циклах, например:    s = s .. s1 расход вычислительных ресурсов может резко увеличивается. На каждом выполнении  s = s .. s1 в невидимом для вас управлении памятью выполняется по меньшей мере запрос памяти под новый размер s и отказ от памяти s до начала операции. Запрос памяти это достаточно затратная операция, как-то зависящая от размера памяти. Для отказа от памяти в Lua, не считая некоторых случаев, ничего специально не выполняется.  Если на некоторую область памяти нет ссылок из существующих в текущий момент объектов скрипта, то она считается неиспользуемой (мусорной). Но чтобы мусор не накапливался (это никем не используемая память ПК), в Lua время от времени запускается сборка мусора (одна из наиболее сложных операций, выполняемых "под капотом" Lua). Сборка мусора тоже использует вычислительные ресурсы скрипта.
 
В моем предыдущем комментарии был ответ на фразу Незнайки. Как при цитировании подцепился Владимир, для меня большая загадка. Возможно, это его хак :smile:
 
TGB, Владимир хакеров на дух не переносит. :smile:  
 
Цитата
Владимир написал:
TGB , Владимир хакеров на дух не переносит.  
  Тогда, за необоснованное подозрение, извините.
 
TGB, Так это он хакеров не переносит, а "необоснованное подозревающих" - вполне. :smile:  
 
Зацепился глазом за:
Цитата
Владимир написал:
Lua-таблицы это, ваще-то, деревья.
 Этим вы можете вносить смуту в не окрепшие умы :smile:
Все-таки таблицы это таблицы. С помощью них можно строить кольца, сети. списки, стеки, очереди и, наконец, деревья.
 
TGB, Да хрен с ними, с  "неокрепшими умами" - пущай укрепляются! Не в инкубаторе же их держать! :smile:

Все-таки это таблицы как деревья. С обращениям к их элементам как к многомерным массивам. И ничего не надо "с помощью них строить" - всё уже построено. Мой ТРЕТИЙ коммент в этот форум содержал фразу:

В общем, с языком почти всё ясно: граф (точнее, дерево) объектов построить можно, а простейшую таблицу или даже массив - нельзя. Остаётся разобраться со строковыми переменными: способна ли эта loadstring интерпретировать строки как операторы языка (или, скажем, функции), то есть имеется ли здесь техническая возможность программирования данными.
 
Цитата
Владимир написал:
TGB, Да хрен с ними, с  "неокрепшими умами" - пущай укрепляются! Не в инкубаторе же их держать! ::

Все-таки это таблицы как деревья. С обращениям к их элементам как к многомерным массивам. И ничего не надо "с помощью них строить" - всё уже построено. Мой ТРЕТИЙ коммент в этот форум содержал фразу:

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

Не нужно слушать этот бред.

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

функция loadstring является deprecated.
www.bot4sale.ru

Пасхалочка для Алексея Иванникова: https://forum.quik.ru/messages/forum10/message63088/topic7052/#message63088
 
s_mike@rambler.ru, Да, Вам слушать этот бред явно противопоказано. :smile:

Меня это блеяние про МОЖНО сделать достало ещё много лет назад. Так СДЕЛАЙТЕ, наконец, "простейшую таблицу под любым соусом при помощи метаметодов", чтобы у таблицы заявок строки не пропадали при обрыве связи! Что, не можете? Способны только языком чесать? А что происходит с этими долбаными таблицами "с любыми свойствами" после DeleteRow - не подскажете? А то я от этого говна вообще отказался. Что до loadstring - эта "deprecated" чуть ли не единственная приличная функция во всём языке, и я ею активно пользуюсь.
 
Цитата
Владимир написал:
   s_mike@rambler.ru, Да, Вам слушать этот бред явно противопоказано. ::

Меня это блеяние про МОЖНО сделать достало ещё много лет назад. Так СДЕЛАЙТЕ, наконец, "простейшую таблицу под любым соусом при помощи метаметодов", чтобы у таблицы заявок строки не пропадали при обрыве связи! Что, не можете? Способны только языком чесать? А что происходит с этими долбаными таблицами "с любыми свойствами" после DeleteRow - не подскажете? А то я от этого говна вообще отказался. Что до loadstring - эта "deprecated" чуть ли не единственная приличная функция во всём языке, и я ею активно пользуюсь.

вам следует научиться различать  таблицы языка луа и оконный табличный интерфейс расширения qlua.

Владимир, вы хам и невежда. Я больше вам писать не буду. К сожалению, на этом форуме невозможно заблокировать вас и не читать то, что вы пишете.

поэтгму я предлагаю остальным посетителям форума более не отвечать вам с целью очищения атмосферы от запахов.
www.bot4sale.ru

Пасхалочка для Алексея Иванникова: https://forum.quik.ru/messages/forum10/message63088/topic7052/#message63088
 
s_mike@rambler.ru, Лапуль, мой скрипт давным-давно работает, и давным-давно торгует лучше меня. И не Вам указывать, чему там мне "следует научиться". Вы меня не интересуете вообще никак - я Вам, кажется, уже это говорил, и Ваш поросячий визг меня абсолютно не колышет: не будете встревать в разговор с идиотскими комментами - не трону. Вот какого хрена Вы сегодня опять влезли? Битому неймётся? Да и "запахи" здесь от таких, как Вы. :wink:  
 
Цитата
Владимир написал:
Ваш поросячий визг меня абсолютно не колышет:
 Владимир, вы себя ведете на форуме очень грубо. Ангелов на форуме нет (это я отношу и к себе), но вы выделяетесь. Все таки мы находимся не в подворотне. На выподы против вас можно отвечать и по интеллигентнее.
 
TGB, Поверьте, у меня ОГРОМНЫЙ опыт общения! В том числе, опыт "затыкания пасти" флудерам.Я пробовал практически все способы, и этот оказался наиболее эффективным - я его даже назвал "идеальный стиль общения".  :smile: А груб я только с хамами, да и то веду себя с ними намного вежливее, чем они со мной.
 
Цитата
Владимир написал:
я его даже назвал "идеальный стиль общения".
  Я в этом не уверен.
  Посмотрите мои комментарии. Ни одного грубого слова, в том числе, и по отношению к вам. Но, хамство, иногда проявляемое  в отношении меня, как мне кажется (но, возможно, я ошибаюсь) быстро исчезает.
  Для вас, как  я это понимаю, общение на этом форуме ценная возможность. И мне кажется, что вам не стоит настраивать пользователей против себя.
 
TGB, Так и Вы мне вполне симпатичны - откуда взяться хамству? Ща, посмотрю какую-нить выжимку из описания моего "идеального стиля общения"...
 
TGB, Начал было обрезать описание, но быстро утомился. В общем, вот он, мой "идеальный стиль" во всей красе:

Стиль мой не ругал только ленивый. Особенно часто это делают мои друзья, которые бывают иногда весьма убедительны. Тем не менее, я считал и считаю, что стиль у меня практически идеальный.
...
Речь идёт, разумеется, только о форме общения - содержание достаточно неплохо описывается пушкинским: "Для власти, для ливреи не гнуть ни помыслов, ни совести, ни шеи". А по форме претензии ко мне такие:

Вов, а ты не допускаешь, что люди просто не терпят такого стиля общения? Я ведь тоже такое очень не люблю и делаю исключение только для тебя. Хотя в голове у меня как-то плохо совмещается твой ум, начитанность и такой язык.
Вова, найди хоть одного человека, который бы видел тебя больше одного-двух раз в сети, но ни разу не наблюдал бы твоего махания шашкой и не пытался бы от него отговорить. Это что - случайное совпадение?
Людям всегда необходимо время, чтобы присмотреться друг к другу. А ты порой при знакомстве вместо руки подаёшь сразу ногу с разворота. Смысл?
Да, собеседник равен мне. Именно поэтому я стараюсь не допускать в общении резких движений, поощрять хорошее больше, чем тыкать носом в плохое - делать ровно то же, чего я хотела бы видеть по отношению к себе. И что-то я не слышу от собеседников тех эпитетов, которыми они награждают тебя. Ты умеешь общаться как я, это я знаю. И равенство сторон от этого не страдает абсолютно. Почему не пользуешься? Чем "идеальнее" твой стиль? Зачем тебе все эти эпитеты и стада бегающих за тобой по пятам "поклонников"?
Когда ты вытравливаешь своей манерой троллей из ветки - ну как-то ещё можно понять, хоть и с натяжкой. А с остальными что? Если ты хочешь чтобы твои умные мысли хотя бы просто начали воспринимать, ну не бей сразу по лицу, не делай сам так, чтоб человек рефлекторно жмурился
Понятно, твой стиль "идеальнее" при определённых условиях - когда "все свои" и когда общение идёт не столько ради общения, обмена мнениями, а когда оно фон - работы ли, досуга, словом, когда помимо собственно общения идёт ещё какой-то процесс в хорошо знакомой уже, сработанной компании. Там и правда форма не на втором, а уже на десятом плане. Естественным образом. Но в сетевой беседе со знакомыми, а часто и с малознакомыми людьми форма намного важнее, весомее.

Убедительно? Убедительно. Да я и сам прекрасно знаю, что "встречают по одёжке". Но вот моя точка зрения на это дело, тоже многократно высказываемая в разных местах: да, стиль своеобразный, но это рабочий стиль! Я заранее предполагаю, что оппонент адекватен, что он меня уважает, что он предполагает, что и я его уважаю, что все тезисы (мои или его) есть соответствующее IMHO, что это не нужно проговаривать на каждый чих. У меня нет ни времени, ни желания долго "обнюхиваться" при знакомстве, делать реверансы и т.п. И собеседнику моему, я полагаю, тоже время дорого. Так зачем же нам фигнёй заниматься, приплясывать друг перед другом - в тыщу раз эффективнее сразу поверить, что перед тобой нормальный, хороший человек, что с ним можно обмениваться эмоциональными, то бишь максимально информативными сообщениями. Господа, ну ведь это же так просто!

Да, "реверансы в обществе всячески приветствуются", люди считают их признаком воспитания и всё такое. Это так называемый "свет" - когда есть некий прописанный дресс-код, типа "в ресторан без галстука нельзя". Бездельникам делать нечего - вот они и раскланиваются. В рабочем же коллективе вполне может оказаться тем самым "реверансом" просто обычное включение новичка в работу, как равного, без церемоний! Я знаю, в видел их глаза в такие моменты! Меня и самого в своё время именно так брали за жопу "бабушки и дедушки отечественного авиастроения"! Это и есть вежливость! Это и есть уважение! Потрясающе действует!

Я 15 лет проработал в лаборатории, где все поголовно так общались! И на шашлыки мы ходили обычно всей лабораторией, и там друг на друга орали под водочку, доказывая, чей алгоритм лучше, и начальники у нас были "Мишка", да "Серёга" (не при посторонних, естественно), но и иерархии (даже временные!) строго соблюдались. Более того, я думаю, что если люди реально работают, то этот стиль чуть ли не единственно возможный! Я просто уверен, что творческие коллективы на прорыве (Туполева, Микулина, Королёва, Тимофеева-Ресовского - по барабану) работали именно так. Дресс-код тоже допустим, но он утомляет, и потому гораздо менее эффективен. А этот "мой" стиль лишь с непривычки "режет ухо", но именно он и оказывается самым комфортным при запредельных нагрузках. Тогда форма действительно "оказывается на десятом плане", и кто там "начальник", а кто "дурак" очень часто не имеет значения, и новички в таком коллективе становятся "своими" за считанные дни - за неделю максимум!

Для меня самого было в своё время открытием, что этот стиль возможен не только "в своём кругу", а практически где угодно. Он оказался эффективным даже "для первого знакомства"! Судите сами: этот стиль хронически неприятен всяким "портянкам" и другим троллям, потому как он просто требует наличия мозгов и умения говорить своими словами! Этот стиль вполне комфортен и для друзей, они легко к нему привыкают - обычный формат "без галстуков". Наконец, он достаточно резко бьёт по глазам новичкам, привлекает внимание, сбивает равнодушие, заставляет определиться по отношению к высказываемому тезису (или, на худой конец, к его автору). Одни сплошные плюсы!

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

Да, мои слова часто "выглядят именно наездом или наскоком". Для тех, кто закомплексован, кто ищет эти наскоки, кто не в состоянии поверить собеседнику, кто боится быть им обманутым... да и хрен бы с ними! Следовательно, этот мой стиль не только рабочий, но и фильтрующий всяких закомплексованных! Не говоря уже про штатных троллей. Они с этим стилем не уживаются, он не сдаёт территорию хаму и мерзавцу - он её защищает. А если мы будем себя уважать только на собственной кухне, отдав все публичные площадки хамам и подлецам, то за что, нам, собственно, себя уважать?

Да, я "ответчик". Да и как иначе? Любой диалог есть обмен мнениями, аргументами, согласование позиций. И не с кем-нибудь, а с собеседником, реакция на его высказывания. Но ни одна из моих коммуникаций в сети изначально не имеет "мотивации раздолбать, заткнуть визжащих и добиться капитуляции". Я собеседника по умолчанию уважаю, Ну, а уж дальше - как получится.

Я терпеть не могу "анонимного" визга типа "кто-то кое-где у нас порой" - это классическое поведение портянок, это классическое поведение гебнявых ублюдков, включая Путина. Если уж ты кого-то в чем-то обвиняешь, так будь любезен адресно это делать! Я стараюсь всегда быть конкретным, и говно говном называть строго "индивидуально". Кроме того, я считаю, что любое своё заявление человек обязан защищать, обосновывать - иначе зачем вякал? Хотя бы так: "Я не знаю, почему я так считаю - просто мне так кажется". Вполне нормальное обоснование! Это тоже называется "отвечать за базар"!

Да, я хочу быть услышанным и понятым. Но отнюдь не "кем бы то ни было". Люди мне важны, быдло - нет: любая реакция быдла не может меня ни "окрылить" ни, наоборот, "заставить опустить руки". Я согласен с фразой Ходорковского: "Есть люди, чьё мнение мне радикально безразлично". Да, движение мне тоже нужно, но только не по кругу, и не по синусоиде. Да, я тоже хотел бы "больше позитива", но где, простите, хоть что-то "светленькое" выковырять из всего этого потока мерзости, которая льётся на нас каждый день? Не замечать? Врать? Без меня!

О портянках: мой опыт показывает, что на них как раз нужно тратить время, ибо именно от безнаказанности у них окончательно сносит крышу, и они засирают всё на три мили вокруг своим словесным поносом. Другое дело, что занятие это достаточно неприятное, и мало кому хочется находиться "в этом во всём". Чем эти ублюдки и пользуются. Да и для нормальных людей вовремя получить точный "удар в глаз" бывает очень полезно. Я даже пару раз предлагал кое-где на форумах установить дежурства, дабы шавки визжащие никогда себя в безопасности не чувствовали и, следовательно, не смели бы особо пасти раскрывать. Увы, как и следовало ожидать, идея закончилась полным пшиком. А жаль...

Последнее: я не собираюсь лукавить, заменять фразы "чем-то гипоаллергенным" или "проскакивать пока это место в объяснениях вообще", не собираюсь "сначала показать красивый образ, картинку, как всё будет прекрасно, когда..." Вот "привести примеры какие-то, понятные каждому, нарисовать схему" - могу. Но только не люмпену. Я убеждён, что нельзя найти нечто хорошее в ком-бы то ни было, если он сам не начинает это искать - пущай и собственную задницу от кресла отрывает! Кстати, это как раз "ровно то же, чего я хотел бы видеть по отношению к себе". Идея "обрастает в пути необходимыми деталями и т.д." только в процессе диалога, обратной связи, споров, драк, но никогда при "вещании с броневика"! Я всё время говорю: "Спорьте, бейте меня - я полностью открыт, у меня даже ника сроду не было, ведь разве rybvv это ник"? Но бейте аргументами, чиорт побъери! И ещё: этот мой стиль - он для взрослых. Я много раз говорил открытым текстом, что не перевариваю общения ни "снизу вверх", ни "сверху вниз" - собеседник равен мне! А я - взрослый. Так что и собеседник мой - взрослый! Приплясывать перед ним и трясти погремушками я не намерен. Такой вот у меня "идеальный стиль"...
 
Цитата
Владимир написал:
TGB , Начал было обрезать описание, но быстро утомился. В общем, вот он, мой "идеальный стиль" во всей красе:
 Очень много букв  :smile:
 Если о моем стиле "идеального стиля общения", то всего два пункта:
 1) Не обижай тех, кто готов с тобой конструктивно взаимодействовать.
 2) Не пропускай хамства, тех. кто на этом думает на этом по пиарится.
 
TGB, Так и у меня оба этих пункта есть!  :smile:  
 
Цитата
Владимир написал:
TGB , Так и у меня оба этих пункта есть!    
 Букв слишком много.
 
По поводу многопоточности кстати. Существует классические (т.е. не родом из пьяного угара) имплементации, например LuaLanes. Советую такого рода библиотеки использовать.
 
Цитата
Артем написал:
По поводу многопоточности кстати. Существует классические ...
 Меня не интересуют классические имплементации. С этим разбирайтесь вы.
 
Classics are classics for a reason. На русский не переводятся.
 
Цитата
Артем написал:
По поводу многопоточности кстати.
 Сделайте свою многопоточную систему работы в одном скрипте QLua, и тогда, может быть, я с вами пообщаюсь.
 
TGB, подразумевая что заспавнить вторую вм с аргументами это сложная и нетривиальная задача. Можно конечно изголяться чтобы например глобалки сами синхронизировались, но это вы уже сами себе Буратино.
 
Цитата
Артем написал:
TGB , подразумевая что заспавнить вторую вм с аргументами это сложная и нетривиальная задача. Можно конечно изголяться чтобы например глобалки сами синхронизировались, но это вы уже сами себе Буратино.
 Вы сами, понимаете, что написали?  Все таки вы упорный. Зачем вы нарыватесь?
 
Цитата
Артем написал:
но это вы уже сами себе Буратино.
 Я хотел это оставить на потом, но исходя из того. что, похоже на то. что вы не исправимы:
  1) вы не плохо разбираетесь в языке программирования Lua (это ваш плюс);
  2) у вас много комплексов; и главный комплекс это проблема самодостаточности. когда вам хочется кого то унизить (но вы зря думаете. что я это подходящий объект0.
 
Таблетки примите, уважаемый.
 
Цитата
Артем написал:
Таблетки примите, уважаемый.
 Это все на что способен этот не уважаемый  :smile:
 
TGB, Вот видите? Я же говорю, что мой стиль идеальнее! :smile:  
 
Цитата
Владимир написал:
Я же говорю, что мой стиль идеальнее!  
 Не согласен, я Атема ни разу не обозвал грязными словами. Но, думаю, что от этого ему не сильно легче.
 
После 15 лет общения с людьми посредственного уровня программирования но очень высокого самомнения (вроде вас двоих) я перестал считать нужным удерживать нужный курс беседы когда фокус меняется с посредственного программирования на высокое самомнение.
Страницы: Пред. 1 ... 3 4 5 6 7 След.
Читают тему
Наверх