Перейти к содержимому

ECS

Гуру
  • Публикации

    533
  • Зарегистрирован

  • Посещение

  • Победитель дней

    203

Сообщения, опубликованные пользователем ECS


  1. В 14.01.2022 в 12:19, num_pi сказал:

    Держи готовую функцию. for i = 1, 8 do: здесь поменяй 8, на большее число, если нужно что бы рандомное возвращаемое число было больше. 

    Оставлю свои пять копеек для тех, кому нужно генерировать рандомные числа фиксированной длины. Хотя к теме это относится опосредованно, но мало ли:

    -- Вариант 1
    local function fixedLengthRandom(digits)
      digits = 10 ^ (digits - 1)
      return math.random(digits, digits * 10 - 1)
    end
    
    -- Вариант 2
    local function fixedLengthRandom(digits)
      digits = 10 ^ (digits - 1)
      return math.floor(digits + math.random() * (digits - 1))
    end

    Вместо math.floor для ускорения процесса можно использовать операцию целочисленного деления // 1.0, однако она сохраняет нулевую дробную часть в результате и доступна только в Lua 5.3. На ваше усмотрение, короче. Результат:

    >> fixedLengthRandom(4)
    >> 4981
    
    >> fixedLengthRandom(8)
    >> 15896813
    • Нравится 1

  2. 1 минуту назад, eu_tomat сказал:

    Штука, конечно, прикольная, но я так и не смог придумать, зачем лично мне нужна MineOS. Прошу понять и простить

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

    • Ха-ха 1

  3. 22 минуты назад, eu_tomat сказал:

    Проблему можно решить, если в расчётах использовать не значение interval, а разницу между computer.uptime в моменты запроса getRealTimestamp()

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

    • Нравится 2

  4. Технически в опенкомпах нет потоков, и все ОСи могут лишь софтверно "скакать" с одной операции на другую, периодически блокируя друг друга и выполняя таски по списку. То есть тут всё блокирующее. Если тебя устроит просто отображать TPS раз в N сек, то заюзай таймер. Код для опеноси:

    local event = require("event")
    local computer = require("computer")
    local component = require("component")
    local gpu = component.gpu
    
    -- Возвращает кол-во реальных (не игровых) наносекунд, прошедших с 00:00:00 01.01.1970 до момента изменения файла на диске 
    local function getRealTimestamp()
      -- Получаем виртуального компонента filesystem, где можно создавать временную помойку
      local proxy = component.proxy(computer.tmpAddress())
      local path = "timestamp.tmp"
    
      -- Создаем временный файл
      proxy.close(proxy.open(path, "wb"))
      -- Получаем дату изменения
      local lastModified = proxy.lastModified(path)
      -- Удаляем его
      proxy.remove(path)
    
      return lastModified
    end
    
    -- Стартуем фоновый таймер, обновляющийся раз в 1 сек
    local interval = 1
    local lastModified = getRealTimestamp()
    
    event.timer(
      interval,
      function()
        -- Примерное значение TPS рассчитывается как расхождение между желаемым интервалом в 1 сек и фактическим,
        -- полученным через разницу в датах изменения временного файла
        local tps = interval / (getRealTimestamp() - lastModified) * 20000
        
        -- Выводим значение TPS на экран
        local oldForeground = gpu.getForeground()
        gpu.setForeground(0xFFFFFF)
        gpu.set(1, 1, "TPS: " .. math.floor(tps + 0.5))
        gpu.setForeground(oldForeground)
        
        -- Все операции вывода на экран занимают время, лучше обновить переменную ещё раз для точности
        lastModified = getRealTimestamp()
      end
    )

    Профит:

     

    NWRATGe.png

     

    И для майноси:

    local computer = require("Computer")
    local component = require("Component")
    local GUI = require("GUI")
    local system = require("System")
    
    -- Функция та же
    local function getRealTimestamp()
      local proxy = component.proxy(computer.tmpAddress())
      local path = "timestamp.tmp"
    
      proxy.close(proxy.open(path, "wb"))
      local lastModified = proxy.lastModified(path)
      proxy.remove(path)
    
      return lastModified
    end
    
    -- Добавляем окошко программы в UI
    local workspace, window, menu = system.addWindow(GUI.filledWindow(1, 1, 60, 20, 0xE1E1E1))
    
    -- Создаем текстовый виджет по центру окошка
    local layout = window:addChild(GUI.layout(1, 1, window.width, window.height, 1, 1))
    local text = layout:addChild(GUI.text(1, 1, 0x4B4B4B, "Тут будет TPS"))
    
    -- Вместо event.timer юзаем computer.uptime
    local uptime = computer.uptime()
    
    -- С файликами история та же
    local lastModified = getRealTimestamp()
    local interval = 1
    
    text.eventHandler = function(workspace, text, e1, ...)
      -- Вычисляем, сколько сек прошло с последнего события
      local deltaTime = computer.uptime() - uptime
    
      -- Если прошло больше ожидаемого интервала
      if deltaTime > interval then
        -- Вычисляем TPS
        local tps = deltaTime / (getRealTimestamp() - lastModified) * 20000
        
        -- Обновляем текстовый виджет
        text.text = "TPS: " .. math.floor(tps + 0.5)
        text.width = #text.text
        workspace:draw()
        
        -- Обновляем переменные
        lastModified = getRealTimestamp()
        uptime = computer.uptime()
      end
    end
    
    workspace:draw()

     

    Результат:

     

    EZ4E9IK.png

    • Нравится 2

  5. Еще API компонента не подразумевает буферизации IO-операций, поэтому слишком частые мелкие обращения к компоненту типа fs.write(handle, "1") будут ощутимо медленнее, чем буферизированная обертка из OpenOS. Т.е. если ты прогаешь какой-нибудь EEPROM с сохранением бинарных файлов побайтово, то добавление строкового буфера хотя бы в 1 Кбайт нифигово апнет скорость

    • Нравится 5

  6. 1 час назад, TayzlexBH сказал:

    Кстати, ос очень прожорливая) приходится делать серверные стойки с 4 планками RAM уровня 3.5.

    Отключаешь обои - и вуаля, хватает 2 планок оперативы за глаза, только если не запускать какое-нибудь 3D. Чистая оська в минимальной конфигурации требует ~600 кбайт доступной памяти, и я не сказал бы, что это прям лютые и неадекватные затраты:

     

    image.png.ccae030334424f9e653581bac7f68cdc.png

     

    Такова цена граф. интерфейса в изначально консольной среде: тут уже хз, как извернуться, чтобы "скукожить" граф. буфер, жрущий минимум 400 кбайт, словно избалованный толстый кис. Остальные 200 кбайт объедков достаются юишным объектам, либам и буферам I/O. В целом опенкомпы по концепции не предназначены для подобных юишных извратов, поэтому смиренно жрем, чо дали

    • Нравится 3

  7. 2 часа назад, eu_tomat сказал:

    Какой-либо модификации не подвергался?

    Нет, офк. Я ж скинул аналогичный результат на чистом консольном луа той же версии, так чего на разность модов-то грешить? Загвоздка явно в поведении железяк. Но боюсь, я абсолютно некомпетентен в этом вопросе, чтобы сгенерировать какие-либо выводы. Цпуинфа:

    8 model name      : Intel(R) Xeon(R) Silver 4214R CPU @ 2.40GHz

     

    • Спасибо 1

  8. 7 часов назад, eu_tomat сказал:

    А объяснение было таким. На обычных операциях (если это не обработка длинных строк или преобразование больших таблиц) наибольший вклад в затраты времени даёт интерпретатор Lua. Вклад же полезной нагрузки минимален. Поэтому простая функция, написанная на Lua, будет исполняться дольше функции из стандартных библиотек. И мой опыт всегда подтверждал эту гипотезу.

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

     

    А как быть в нашем случае, когда эквивалентный код под одной VM на различном железе выдает различную производительность?

    • Спасибо 1

  9. 1 час назад, eu_tomat сказал:

    Тогда что влияет? Какие предлагаешь варианты?

    Железо скорее. Луа-консоль запускал на рабочей вдске, сервак кубача поднимаю там же, т.к. сингловый клиент на дешманском ноуте умирает с TLWY даже на 1млн итераций, не говоря уже о 20 млн. С точки зрения дилетанта могу предположить, что наибольшее влияние на однопоточные вычисления оказывает набор инструкций ЦП, объем кеша и частота. Возможно, надо байт-код для каждого метода и каждой машины чекать, чтобы сказать наверняка (он вообще может отличаться для одинаковых версий луа?)

    • Спасибо 1

  10. 6 минут назад, eu_tomat сказал:

    Что-то у тебя интервал времени получился крошечный. Там погрешность получается большая

    Интервал зависит от кол-ва итераций, а оно такое же, как в примере Zer0Galaxy. Тестил я на десктопном некомпилируемом Lua 5.3.1, лень кубач было ставить. Не нравится? Да пожалуйста, вон результат на 2e7 итераций:

    Constant        1.152
    Upvalue         1.375
    math.floor      1.749
    floor (no indexing)     1.425
    Lua 5.3+: num + 0.5 // 1        1.524
    Lua 5.2+: num - num % 1         1.733

    И на опенкомпах:

     

    image.png.8fe5e2f722501522215a38a8129d8854.png

     

    Один фиг победа за первым методом

     

     

    • Спасибо 1

  11. 4 часа назад, Zer0Galaxy сказал:

    Опыт подтверждает твои выводы:

     

    4 часа назад, eu_tomat сказал:

    не хуже должен быть вариант с использованием local floor=math.floor

    Чекнул дополнительно пару известных вариантов округления. Топикстартеру респект за наиболее производительное решение:

    Constant        0.017
    Upvalue         0.023
    math.floor      0.027
    floor (no indexing)     0.025
    Lua 5.3+: (num + 0.5) // 1        0.022
    Lua 5.2+: num - num % 1         0.026

     

    • Нравится 1
    • Спасибо 1
    • В шоке 1

  12. Только что, OpenReactor сказал:

    Сервер то не мой. Ладно тогда время кастылей)

    Дык попробуй отослать MOTD\r\n или MOTD\n, в 90% случаев серваки должны адекватно проинтерпретировать сообщение, если это прям не лютый кастом

    • Спасибо 1

  13. В 20.08.2021 в 22:12, OpenReactor сказал:

    Осталось найти решение

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

     

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

    • Спасибо 1

  14. В 17.08.2021 в 03:36, whiskas сказал:

    да дерево это понятно что круто. Но я думаю легче будет сделать хеш таблицу

    Даже в случае с хеш-таблицей держать все индексы БД в памяти - такая себе затея, т.к. оператива не резиновая, а скрафтить RAID на 12 мбайт не составит особого труда. Основной проблемой при работе с индексами, хранящимися на диске, у тебя будет скорость чтения и реиндексации при записи, т.к. опенкомповские диски прям сильно лимитированы по I/O операциям. Даже если прикрутить к хеш-таблице бинарный поиск, то это слабо поможет жирным БД, исчисляемых мегабайтами, т.к. глубина рекурсии при поиске может достигать нескольких тысяч. К сожалению, чем жирнее БД, тем более заковыристый алгоритм требуется для ее поддержки, и заюзать древовидную структуру для хранения индексов будет оптимально, т.к. для чтения с диска нужно минимизировать число узлов, которые обходит поисковая система. Ну а про удаление/вставку со сдвигом индексов и говорить нечего

    • Спасибо 2

  15. 1 час назад, eu_tomat сказал:

    О какой библиотеке идёт речь? Стандартная библиотека в составе OpenOS не может корректно работать с таким кодом.

    Это особо и не важно, т.к. отсылающий код взят у топикстартера, а запись в сокет, судя по всему, у него работает. Либо это кастомная интернет-либа, либо код выложен не полностью, пофигу. Главное - дать наводку на листенер internet_ready

    • Спасибо 1

  16. 14 часа назад, OpenReactor сказал:

    Я хочу допустим запросить motd ещё раз то я получу nill

    soc:write("MOTD")

    motd = soc:read(100)

    Сокет-сервак работает параллельно с твоим клиентом, пишущим MOTD и ждущим ответа. Клиентские данные могли не успеть обработаться серваком во второй раз, могли проинтерпретироваться в виде сдублированной строки "MOTDMOTD", а могли и вовсе быть поглощены ZOGом во имя вселенского благополучия. Ты же делаешь :read() в слепой надежде на успех. Непорядок! Подписывайся на ивент internet_ready, делай небольшую задержку между отправкой запросов на MOTD, разбивай сообщения через символ переноса строки, правильно обрабатывай их на сервере, а затем уже читай данные:

    local soc = require("internet")
    local event = require("event")
    
    event.listen("internet_ready", function()
      local motd = soc:read(100)
      ...
    end)
    
    soc.open("localhost", 2888)
    
    soc:write("MOTD\r\n")
    os.sleep(1)
    
    soc:write("MOTD\r\n")
    os.sleep(1)
    ...

    Либо, если оч сложна, юзай костыль со слипом. Но тут тоже никаких гарантий, то данные пришли и обработались корректно:

    local soc = require("internet")
    soc.open("localhost", 2888)
    
    soc:write("MOTD")
    os.sleep(1)
    motd = soc:read(100)
    
    soc:write("MOTD")
    os.sleep(1)
    motd = soc:read(100)
    ...

     

     

    • Спасибо 1

  17. Оптимизированы наиболее часто используемые методы библиотеки Screen, работающей с экранными буферами: если ранее для каждого рисуемого пикселя выполнялась проверка вхождение в регион отрисовки, то теперь все прямоугольные команды автоматически рекомпонуются, чтобы уместиться в этот регион. Странно, что это не было сделано изначально, но тем не менее скорость перемещения сложных оконных приложений с кучей мелких прямоугольников и картинок (типа местного Finder) ощутимо подросла

     

    Ну и забавы ради добавлен метод screen.blur(), применяющий эффект размытия к указанному региону и, опционально, накладывающий цветовой фильтр, а также виджет GUI.blurredPanel, чтобы создавать окна с заливкой в стиле AcrylicBrush из UWP

     

    Вообще изначально было реализовано полноценное размытие по Гауссу, но, учитывая мизерные размеры экранов, оказалось, что простого box blur будет более чем достаточно, и визуальной разницы нет. Вопрос прожорливости остается за кадром:

     

    3ADdQRc.gif

    • Нравится 3
    • Спасибо 1

  18. Callback-функции типа onTouch/onResize существуют только для отдельно взятых элементов, а не для каждого GUI.object. Поэтому проще всего "заоверрайдить" метод :close() для закрытия окна, как это сделано в приложениях типа 3D Print. По итогу что в случае callback-функций нужно создавать лишнюю функцию, что в случае "оверрайда", поэтому тут дилемма скорее эстетического характера

    local baseWindowClose = window.close
    window.close = function(...)
      -- Профит
    
      baseWindowClose(...)
    end

     

    • Нравится 2
×
×
  • Создать...