Re: библиотека lua_share (обмен данными между скриптами lua)
вот: [url]https://github.com/untoxa/lua_share/commit/2a39b17519f9d7822498b568abf6308d74cb964c[/url]
бинарники: [url]https://github.com/untoxa/lua_share/releases/latest[/url]
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
QUIK -> DDE → Написание внешних библиотек на C++/Delphi/C# для Lua → библиотека lua_share (обмен данными между скриптами lua)
вот: [url]https://github.com/untoxa/lua_share/commit/2a39b17519f9d7822498b568abf6308d74cb964c[/url]
бинарники: [url]https://github.com/untoxa/lua_share/releases/latest[/url]
вот: [url]https://github.com/untoxa/lua_share/commit/2a39b17519f9d7822498b568abf6308d74cb964c[/url]
бинарники: [url]https://github.com/untoxa/lua_share/releases/latest[/url]
Спасибо. Я тут пока обнаружил небольшой inconsistency.
local ns = sh.GetNameSpace("test_name_space")
val = ns:DeepCopy() -- nil
ns["hello"] = nil
val = ns:DeepCopy() -- {}
Было бы хорошо, чтобы всегда пустой NameSpace как nil возвращался, т.к. иногда нужно делать DeepCopy() в очень частом цикле (sleep(1)) и 99.9% времени он пуст. И чтобы не плодить в garbage пустые таблицы.
При этом не нужно его там физически в памяти удалять, просто возвращать из dll nil, а не пустую копию, если там пусто.
вот: [url]https://github.com/untoxa/lua_share/commit/2a39b17519f9d7822498b568abf6308d74cb964c[/url]
бинарники: [url]https://github.com/untoxa/lua_share/releases/latest[/url]
Можно унифицировать __call для IPC как говорили? Сейчас вот такая реализация гасит сервер при ns('pop'), наверно ищет глобальную. Не знаю, зачем кому-то нужно именно глобальную запускать, когда можно сразу определить ее в каком-то неймспейсе. Ну если нужно, то для глобальных особый неймспейс globals..
__default_namespace_metatable = {
__newindex = function(self, key, value)
self.__data[key] = value
end,
__index = function(self, key)
return self.__data[key]
end,
__call = function(self, f, ...)
if f=='get' then return self.__data end
if f=='pop' then
local data = self.__data
if data~=nil and next(data) then
self.__data = {}
else data = nil
end
return data
end
return self[f](...)
end
}
И насчет итерирования, о котором вы говорили. Вы предполагали осуществлять блокирование неймспейса на все его итерирование? Иначе это не корректно, он может меняться. Сейчас можно просто взять DeepCopy и по ней итерировать.
..Обнаружил проблему. Как минимум DeepCopy() в IPC в новой сборке работает на порядок медленнее. А может и остальное. С чем это связано? Просто меняю обратно 2 dll - получаю предыдущую скорость. Может сборка без оптимизаций?
Было бы хорошо, чтобы всегда пустой NameSpace как nil возвращался, т.к. иногда нужно делать DeepCopy() в очень частом цикле (sleep(1)) и 99.9% времени он пуст. И чтобы не плодить в garbage пустые таблицы.
это не очень хорошая идея использовать DeepCopy в частом цикле, хотя, зависит от величины таблицы, конечно.
проверять на пустоту и возвращать nil если нет элементов идея не очень хорошая. создайте table.value = 1, потом сделайте table.value = nil. table станет {} а не nil. ровно это мы и наблюдаем. к тому же, нужно проверять на пустоту, а это нетривиальная задача, не в смысле реализации, а в смысле определения подхода: что считать пустотой.
если вас беспокоит неопределенность, используйте val = (ns:DeepCopy() or {})
И насчет итерирования, о котором вы говорили. Вы предполагали осуществлять блокирование неймспейса на все его итерирование? Иначе это не корректно, он может меняться. Сейчас можно просто взять DeepCopy и по ней итерировать.
нет, не предполагал. если вам нужна блокировка - итерируйте копию.
..Обнаружил проблему. Как минимум DeepCopy() в IPC в новой сборке работает на порядок медленнее. А может и остальное. С чем это связано? Просто меняю обратно 2 dll - получаю предыдущую скорость. Может сборка без оптимизаций?
понятия не имею. мне кажется это сомнительным, так как ни код, ни компилятор, ни параметры сборки не менялись. все изменения видны в гите. ничего из того, что бы затрагивало данный функционал, не менялось.
я не вижу причин блокировать таблицу во время итерирования. если нужна блокировка - всегда можно сделать ее самостоятельно при помощи флагов внутри общего хранилища.
я не вижу причин блокировать таблицу во время итерирования. если нужна блокировка - всегда можно сделать ее самостоятельно при помощи флагов внутри общего хранилища.
Просто не видно практической необходимости итерировать без блокирования. Этак она может перестроиться так, что даже повторно элементы проитерируются.. ) Ладно, не важно, это я к слову.
А вот такой метод get в __call будет работать по скорости примерно одинаково с DeepCopy?
Этак она может перестроиться так, что даже повторно элементы проитерируются.. )
нет. из-за особенностей реализации next()
А вот такой метод get в __call будет работать по скорости примерно одинаково с DeepCopy?
какой?
какой?
Выше по поводу __call в IPC и кусок кода метатаблицы для неймспейса. Вызов ns('get'), должен работать аналогично DeepCopy
Выше по поводу __call в IPC и кусок кода метатаблицы для неймспейса. Вызов ns('get'), должен работать аналогично DeepCopy
никакой разницы. код, который копирует результат один и тот же. немного медленнее из-за вызова метаметода __call(), но это довольно мало.
Андрей_ пишет:Выше по поводу __call в IPC и кусок кода метатаблицы для неймспейса. Вызов ns('get'), должен работать аналогично DeepCopy
никакой разницы. код, который копирует результат один и тот же. немного медленнее из-за вызова метаметода __call(), но это довольно мало.
Хорошо. Добавьте пожалуйста поддержку __call в неймспейсах для IPC. Проксирование как в не-IPC.
пожалуйста: [url]https://github.com/untoxa/lua_share/commit/2ad9468a9dff3f6732ff3a437fd37934740cea6f[/url]
пожалуйста: [url]https://github.com/untoxa/lua_share/commit/2ad9468a9dff3f6732ff3a437fd37934740cea6f[/url]
Собрал, проверю. И добавил на всякий случай ключ оптимизации -O3. Есть какие-то причины этого не делать?
И нашел, что же тормозит. Это просто sleep(1). Вот сейчас стабильно этот код в квике работает 15.4 сек, а не 1 сек. Но днем с этим проблем не было. Не знаете, что может быть? Причем я пробовал и квиковский sleep и сокетовый, результат одинаков. Причем он такой же и для sleep(10).
local sleep=sleep
for i=0,1000 do
sleep(1)
end
..после нескольких перезапусков квика сейчас 1.5-1.6с. Не пойму от чего зависит.
Вот, похоже эта проблема. Как исправить видимо на уровне ОС,чтобы не было переключения какого-то
[url]https://stackoverflow.com/questions/23258650/sleep1-and-sdl-delay1-takes-15-ms[/url]
И все это для реализации RPC вызова в другом макросе\квике. Вы говорили только через опрос со sleep можно?
Может еще как-то можно? Sleep(0) приводит к видимой загрузке в простое, а Sleep(15) - много. timeBeginPeriod(1) не сильно портит жизнь ОС\батарее и т.п.?
NtSetTimerResolution()
NtSetTimerResolution()
не работает в последних сборках Windows 10 на глобальном уровне. Надо как-то вызывать это из/для самого процессса.
[url]https://habr.com/ru/post/522212/[/url]
У меня все утилиты показывают текущее разрешение 1мс. А Sleep(1) в квике все равно работает 15.5мс. Но так и не понятно, как он иногда переходит на 1.5мс.
Интересно, если бы такая ф-ция появилась в lua_share.dll для вызова, это работало бы.. )
library lua_mmtimer;
uses windows;
type NTSTATUS = ULONG;
const STATUS_SUCCESS = NTSTATUS(0);
function NtQueryTimerResolution(LowRes: PULONG; HighRes: PULONG; CurrRes: PULONG): NTSTATUS; stdcall; external 'ntdll.dll' name 'NtQueryTimerResolution';
function NtSetTimerResolution(RequestedRes: ULONG; Set_: Boolean; ActualRes: PULONG): NTSTATUS; stdcall; external 'ntdll.dll' name 'NtSetTimerResolution';
function luaopen_lua_mmtimer(ALuaInstance: pointer): longint; cdecl;
var ResSet: ULONG;
begin
NtSetTimerResolution(5000, true, @ResSet);
result:= 0;
end;
exports
luaopen_lua_mmtimer name 'luaopen_lua_mmtimer';
end.
для использования просто пишете:
mt = require "lua_mmtimer"
и всё
Спасибо! Вот и моя первая dll для квика. Кажется теперь понимаю, почему вы выбираете паскаль для этого )
вот: [url]https://github.com/untoxa/lua_share/commit/2a39b17519f9d7822498b568abf6308d74cb964c[/url]
бинарники: [url]https://github.com/untoxa/lua_share/releases/latest[/url]
А почему индексные метаметоды создают объект, а call - нет? Это не удобно, т.к. для надежности всегда после GetIPCNameSpace надо что-то в него пробрасывать. Вдруг () вызовется раньше.. При этом еще и сервер очень неприятно слетает, даже квик перезапускать приходится. С таким успехом можно всегда создавать объект в GetIPCNameSpace. Но лучше, чтобы все метаметоды одинаково инициализировали в этом плане. Какие доводы против инициализации call-ом?
я не проверяю, существует объект для вызова или нет. проглатывать ошибки неправильно.
сейчас просто достаем объект, не важно какой, может быть таблица, а может функция, что угодно, и пытаемся его вызывать. если это функция или что угодно с метаметодом __call(), то он вызовется.
то есть не нужно для глобальных функций делать прокси из таблицы с метаметодом __call().
а раз так, то непонятно: что создавать? и почему именно это?
то, что квик виснет - неприятно. наверное, нужно добавить тайм-аут ожидания ответа.
я не проверяю, существует объект для вызова или нет. проглатывать ошибки неправильно.
сейчас просто достаем объект, не важно какой, может быть таблица, а может функция, что угодно, и пытаемся его вызывать. если это функция или что угодно с метаметодом __call(), то он вызовется.
то есть не нужно для глобальных функций делать прокси из таблицы с метаметодом __call().
а раз так, то непонятно: что создавать? и почему именно это?
то, что квик виснет - неприятно. наверное, нужно добавить тайм-аут ожидания ответа.
И все же, почему отличаются подходы чтения через [] и запуска через () для свежеполученного неймспейса?
Оба метоаметода определены в одном месте. Но только второй требует некоей доп. инициализации где-то внутри. Которая достигается через обращение к [] сперва:
ns["test"] = "Hello, world" -- must ensure test_name_space exists, call does not create the object
А ns["test"] не "must ensure test_name_space exists", т.к. само делает "create the object"
не совсем понял что вы имеете в виду в двух последних строках, возможно что-то напутали. так вот:
ns["key"] = "value"
однозначно определяет, что вы хотите присвоить ключу "key" значение "value" в некой таблице. если таблицы нет, то мы ее создаем.
когда мы делаем ns("param") и ns у нас не существует, то что нам создать, таблицу? а у этой таблицы будет метаметод __call()? с чего бы? а если boot удалить?
кроме того, как я сказал, ns не обязательно должна быть таблицей. может быть глобальной функцией. тогда ns("param") можно сделать, а ns["key"] = "value" - нельзя (ну или можно, если функции присвоить метатаблицу с метаметодами __index и __newindex, но это из разряда курьезов).
в общем, я не вижу особого смысла в том, чтобы создавать объект при вызове его как функции.
ns["key"] = "value"
однозначно определяет, что вы хотите присвоить ключу "key" значение "value" в некой таблице. если таблицы нет, то мы ее создаем.
когда мы делаем ns("param") и ns у нас не существует, то что нам создать, таблицу? а у этой таблицы будет метаметод __call()? с чего бы? а если boot удалить?
ns мы получили не произвольно, а явно указав, что это неймспейс "x". "x" определен в boot, либо применяется политика по умолчанию - таблица. Т.к. смысла быть неопределенной ф-цией нет ) Поэтому нет никакой неопределенности что создавать. ns("param") однозначно определяет, что вы хотите вызвать __call в объекте "x" из boot, либо таблице по умолчанию. Естественно, разработчик либо обеспечивает __call() в "x", либо в __default_namespace_metatable, которое по умолчанию назначается всем таблицам. Если зачем-то удалить boot (в чем пользы и смысла нет совсем), вот тогда можно и получать ошибку.
А иначе мы в итоге имеем то, что __call это мегаполезно и будет использоваться 90% проектов, но нужно всегда самому пробрасывать в индекс ненужное, иначе будет плохо. А значит, для надежности всегда делать это после GetNameSpace. Учитывая, что и без использования call не так много смысла в отложенном создании таблицы под GetNameSpace, лучше уж создавать ее всегда сразу, если ее нет. Внутри GetNameSpace. Не получая доп рисков ошибок и cold run инициализации при первом использовании.
Я, кстати, и не предполагал, что через ns = GetIPCNamespace("x") можно сослаться на глобальную ф-цию х. Это не описано. А точно ли можно? Впрочем, это было бы лишним нагромождением.
я не считаю, что __call это мегаполезно и нужно использовать это повсеместно.
просто пишите код аккуратно и никаких проблем не будет. слишком много умолчаний и подавление ошибок - это плохо, ведет к неочевидным проблемам в будущем.
да, можно сослаться на глобальную функцию. да, не описано, потому что я изменения в поведении __call не описывал в доке.
local sh = require "lua_share"
sh['test']=1
Когда не используется неймспейс, переменные создаются в _G, или в какой-то неявной таблице\неймспейсе?
QUIK -> DDE → Написание внешних библиотек на C++/Delphi/C# для Lua → библиотека lua_share (обмен данными между скриптами lua)
Форум работает на PunBB, при поддержке Informer Technologies, Inc