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

Fingercomp's Playground

  • записи
    92
  • комментария
    373
  • просмотров
    221 720

Пара трюков OpenComputers

Fingercomp

2 172 просмотра

Здесь опишу такие штучки, которые могут потребоваться продвинутым OC-программистам (да и просто Луа-программистам).

 

Busy Idle
С помощью этого трюка можно делать довольно точные задержки, причём с длительностью менее тика.

local lastSleep = os.clock()local function sleep(t)  local begin = os.clock()  while os.clock() - begin < t do    if lastSleep - os.clock() >= 3.5 then -- В конфигурации дефолтное значение = 5 секунд, ставим на 1.5 меньше для безопасности.      os.sleep(0.05) -- Вынужденная задержка.      lastSleep = os.clock()      t = t - 0.05    end  endend


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

local function isin(tbl, value)  for k, v in pairs(tbl) do    if v == value then	  return true, k    end  end  return falseend


На огромных массивах может и затормозить — скорость работы прямо зависит от длины массива.

 


Табличная магия
Рассмотрим этот на первый взгляд обычный пример кода:

local tbl1 = {"My", "super", "table", 42}local tbl2 = tbl1tbl2[2] = "cool"for _, tbl in pairs({tbl1, tbl2}) do -- Напечатать значения таблиц  for k, v in pairs(tbl) do    print(k, v)  endend


Многие уверены, что вывод будет такой:

1 My2 super3 table4 421 My2 cool3 table4 42


Но вместо этого получаем:

1 My2 cool3 table4 421 My2 cool3 table4 42


Как видно, изменив значение в одной таблице, изменилась и другая.
Дело в том, что переменная хранит указатель на таблицу, а не саму таблицу. Соответственно, и tbl1, и tbl2 ссылаются на один и тот же массив.
На первый взгляд это кажется ненормальным. Как скопировать-то таблицу?

local function copy(tbl)  if type(tbl) ~= "table" then return tbl end  local result = {}  for k, v in pairs(tbl) do    result[k] = copy(v)  end  return resultend


Но из этого можно извлечь очень полезное применение. Когда мы передаём таблицу в аргументы функции, массив не копируется, а даётся указатель на тот же самый. Поэтому можно сообразить такой код:

local function removeOddNums(tbl)  for k, v in pairs(tbl) do    if tonumber(v) and v % 2 == 1 then      tbl[k] = nil    end  endend local table = {5, 26, 249586, 457139, 876, 42, 153}removeOddNums(tbl)


И он будет работать. Этим и объясняется, почему table.sort не возвращает таблицу. У меня не самое полезное применение, однако с помощью таблицы можно создавать "поинтеры", например, так: local numPtr = {42}, а в функциях использовать так: local value = numPtr[1]; numPtr[1] = 666. И уже использовать их в своих вычислениях.

 


Думаю, вы найдёте применение этим фокусам. Не самые очевидные моменты, однако иногда требуется.
The end.

  • Нравится 4


9 комментариев


Рекомендуемые комментарии

Оу, классно! Не ожидал от Lua возможности даже имитировать указатель на переменную.

Но у меня сомнения относительно os.clock(). Всегда думал, что это время, затраченное процессором на выполнение кода, а оно совпадает с реальным временем лишь в случае, когда процессор 100% своего времени тратит на выполнение кода именно на этом компьютере. Что-то типа активной части uptime.

Поделиться комментарием


Ссылка на комментарий

Оу, классно! Не ожидал от Lua возможности даже имитировать указатель на переменную.

Но у меня сомнения относительно os.clock(). Всегда думал, что это время, затраченное процессором на выполнение кода, а оно совпадает с реальным временем лишь в случае, когда процессор 100% своего времени тратит на выполнение кода именно на этом компьютере. Что-то типа активной части uptime.

Верно, правда, почему-то решил, что в machine.lua используется время компьюетра. Но нет.

В конфигурации OpenComputers есть настройка timeout, равная 5 реальным (не игровым) секундам по умолчанию. Обновил код.

Поделиться комментарием


Ссылка на комментарий

Пришлось вернуться к os.clock: аптайм давал неточное время.

Мы можем здесь положиться на клок, так как этот код не будет делать yield во время слипа, только при вынужденном торможении (и тогда разность будет незначительна).

Поделиться комментарием


Ссылка на комментарий

Пришлось вернуться к os.clock: аптайм давал неточное время. Мы можем здесь положиться на клок, так как этот код не будет делать yield во время слипа, только при вынужденном торможении (и тогда разность будет незначительна).

На практике же выходит значительная разница

c0=os.clock() t0=computer.uptime() for i=1,10^7 do end print(os.clock()-c0,computer.uptime()-t0)
-- 2.92   2.94
c0=os.clock() t0=computer.uptime() for i=1,1000 do os.sleep(0.05) end print(os.clock()-c0,computer.uptime()-t0)
-- 2.37  71.4
Само по себе использование os.sleep(0.05) неявно делает yield.

Поделиться комментарием


Ссылка на комментарий

Там даже ещё круче завернули.

os.sleep => event.pull => repeat computer.pullEvent until deadline

Как же тут хромает задержка, ох. Так что os.clock определённо.

Поделиться комментарием


Ссылка на комментарий

Да, я видел, как там завернуто. Но это как раз таки понятно: задержка – лучшее время для обработки событий. В пределах тика задержка вполне себе удовлетворительная, если обработчики событий не ресурсоемкие.

К задержам без sleep (без yield) я отношусь плохо, т. к. это шаг к лагодрому. Но если задержка длится миллисекунды и используется раз в минуту, то почему бы и нет.

Поделиться комментарием


Ссылка на комментарий

Ну это верно.

Мне такая задержка потребовалась для плеера: там тик длиться может 1/720 секунды, а то и больше. Разумно использовать здесь busy-idle. Что я и сделал.

Поделиться комментарием


Ссылка на комментарий

Это я не то написал. Функция, конечно, рекурсивная, потому вызывать должна саму себя. Поправил.

Поделиться комментарием


Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Добавить комментарий...

×   Вы вставили отформатированное содержимое.   Удалить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...