Самый простой способ заставить lua-скрипт подождать / приостановить / перевести в спящий режим / заблокировать на несколько секунд?

StackOverflow https://stackoverflow.com/questions/1034334

  •  06-07-2019
  •  | 
  •  

Вопрос

Я не могу понять, как заставить lua выполнять какие-либо распространенные временные трюки, такие как

  • sleep - остановить все действия в потоке

  • пауза/ожидание - не переходите к следующей команды, но и позволит другим кодом в приложения для продолжения

  • блокировать - не переходите к следующей команде, пока не вернется текущая

И я читал, что a

while os.clock()<time_point do 
--nothing
end

съедает процессорное время.

Есть какие-нибудь предложения?Есть ли вызов API, который я пропускаю?

Обновить:Я написал этот вопрос давным-давно, пытаясь заставить WOW Lua воспроизводить действия по расписанию (т. Е.встаньте, подождите 1 секунду, потанцуйте, подождите 2 секунды, сядьте.Без пауз все это происходит почти за одну и ту же четверть секунды.) Как оказалось, WOW намеренно отключил практически все, что позволяет выполнять действия в режиме ожидания, потому что это могло нарушить работу игры или включить ботов. Я решил, что для воссоздания часов после их удаления мне придется сделать что-то сумасшедшее, например, создать рабочий массив (с действием и временем выполнения), а затем зарегистрировать обработчик событий для множества обычных событий, таких как перемещение мыши, затем в обработчике even обработать любое действие, время которого пришло.Обработчик событий на самом деле не выполнялся бы каждые X миллисекунд, но если бы это происходило каждые 2-100 мс, это было бы достаточно близко.К сожалению, я никогда не пробовал этого.

Это было полезно?

Решение

Это не становится проще, чем это.Переход в спящий режим может быть реализован в вашем FLTK или что-то еще, но здесь рассматриваются все лучшие способы перевода системы в спящий режим стандартного типа без прерываний по специальным событиям.Узрите:

-- we "pcall" (try/catch) the "ex", which had better include os.sleep
-- it may be a part of the standard library in future Lua versions (past 5.2)
local ok,ex = pcall(require,"ex")
if ok then
   -- print("Ex")
   -- we need a hack now too? ex.install(), you say? okay
   pcall(ex.install)
   -- let's try something else. why not?
   if ex.sleep and not os.sleep then os.sleep = ex.sleep end
end

if not os.sleep then
   -- we make os.sleep
   -- first by trying ffi, which is part of LuaJIT, which lets us write C code
   local ok,ffi = pcall(require,"ffi")
   if ok then
      -- print("FFI")
      -- we can use FFI
      -- let's just check one more time to make sure we still don't have os.sleep
      if not os.sleep then
         -- okay, here is our custom C sleep code:
         ffi.cdef[[
            void Sleep(int ms);
            int poll(struct pollfd *fds,unsigned long nfds,int timeout);
         ]]
         if ffi.os == "Windows" then
            os.sleep = function(sec)
               ffi.C.Sleep(sec*1000)
            end
         else
            os.sleep = function(sec)
               ffi.C.poll(nil,0,sec*1000)
            end
         end
      end
   else
      -- if we can't use FFI, we try LuaSocket, which is just called "socket"
      -- I'm 99.99999999% sure of that
      local ok,socket = pcall(require,"socket")
      -- ...but I'm not 100% sure of that
      if not ok then local ok,socket = pcall(require,"luasocket") end
      -- so if we're really using socket...
      if ok then
         -- print("Socket")
         -- we might as well confirm there still is no os.sleep
         if not os.sleep then
            -- our custom socket.select to os.sleep code:
            os.sleep = function(sec)
               socket.select(nil,nil,sec)
            end
         end
      else
         -- now we're going to test "alien"
         local ok,alien = pcall(require,"alien")
         if ok then
         -- print("Alien")
         -- beam me up...
            if not os.sleep then
               -- if we still don't have os.sleep, that is
               -- now, I don't know what the hell the following code does
               if alien.platform == "windows" then
                  kernel32 = alien.load("kernel32.dll")
                  local slep = kernel32.Sleep
                  slep:types{ret="void",abi="stdcall","uint"}
                  os.sleep = function(sec)
                     slep(sec*1000)
                  end
               else
                  local pol = alien.default.poll
                  pol:types('struct', 'unsigned long', 'int')
                  os.sleep = function(sec)
                     pol(nil,0,sec*1000)
                  end
               end
            end
         elseif package.config:match("^\\") then
            -- print("busywait")
            -- if the computer is politically opposed to NIXon, we do the busywait
            -- and shake it all about
            os.sleep = function(sec)
               local timr = os.time()
               repeat until os.time() > timr + sec
            end
         else
            -- print("NIX")
            -- or we get NIXed
            os.sleep = function(sec)
               os.execute("sleep " .. sec)
            end
         end
      end
   end
end

Другие советы

[Я собирался опубликовать это в качестве комментария к У Джона Кромарти опубликуйте, но не поняли, что вы не можете использовать форматирование в комментарии.]

Я согласен.Перенос его в оболочку с помощью os.execute() определенно сработает, но в целом выполнение вызовов оболочки обходится дорого.Перенос некоторого кода на C будет намного быстрее во время выполнения.На C / C ++ в системе Linux вы могли бы использовать:

static int lua_sleep(lua_State *L)
{
    int m = static_cast<int> (luaL_checknumber(L,1));
    usleep(m * 1000); 
    // usleep takes microseconds. This converts the parameter to milliseconds. 
    // Change this as necessary. 
    // Alternatively, use 'sleep()' to treat the parameter as whole seconds. 
    return 0;
}

Затем, в основном, сделайте:

lua_pushcfunction(L, lua_sleep);
lua_setglobal(L, "sleep");

где "L" - это ваше lua_State.Затем в вашем скрипте Lua, вызываемом из C / C ++, вы можете использовать свою функцию, вызвав:

sleep(1000) -- Sleeps for one second

Если вам случится использовать Луазокет в вашем проекте или просто установили его и не возражаете против его использования, вы можете использовать socket.sleep(time) функция, которая переходит в спящий режим в течение заданного промежутка времени (в секундах).

Это работает как в Windows, так и в Unix, и вам не нужно компилировать дополнительные модули.

Я должен добавить, что функция поддерживает дробные секунды в качестве параметра, т. е. socket.sleep(0.5) будет спать полсекунды.Он использует Sleep() в Windows и nanosleep() в другом месте, поэтому у вас могут возникнуть проблемы с точностью Windows, когда time становится слишком низко.

Вы не можете сделать это в чистом Lua без использования процессора, но есть простой, непереносимый способ:

os.выполнить ("спящий режим 1")

(это заблокирует)

Очевидно, что это работает только в операционных системах, для которых допустимой командой является "sleep 1", например Unix, но не Windows.

для Windows вы можете сделать это:

os.execute("CHOICE /n /d:y /c:yn /t:5")

Функция сна - Использование : sleep(1) -- sleeps for 1 second

local clock = os.clock
function sleep(n)  -- seconds
   local t0 = clock()
   while clock() - t0 <= n do
   end
end

Функция паузы - Использование : pause() -- pause and waits for the Return key

function pause()
   io.stdin:read'*l'
end

надеюсь, это то, что вам было нужно!:Ди - Джо ДФ

Я бы реализовал простую функцию для переноса функции sleep хост-системы в C.

Чистый Lua использует только то , что есть в стандарте ANSI C.Luiz Figuereido's модуль lposix содержит многое из того, что вам нужно для более системных действий.

Для второго запроса пауза / ожидание, когда вы останавливаете обработку в Lua и продолжаете запускать свое приложение, вам нужны сопрограммы.В итоге вы получите некоторый C-код, подобный следующему:

Lthread=lua_newthread(L);
luaL_loadfile(Lthread, file);
while ((status=lua_resume(Lthread, 0) == LUA_YIELD) {
  /* do some C code here */
}

и в Lua у вас есть следующее:

function try_pause (func, param)
  local rc=func(param)
  while rc == false do
    coroutine.yield()
    rc=func(param)
  end
end

function is_data_ready (data)
  local rc=true
  -- check if data is ready, update rc to false if not ready
  return rc
end

try_pause(is_data_ready, data)
require 'alien'

if alien.platform == "windows" then
  kernel32 = alien.load("kernel32.dll")
  sleep = kernel32.Sleep
  sleep:types{ret="void",abi="stdcall","uint"}
else
  -- untested !!!
  libc = alien.default
  local usleep = libc.usleep
  usleep:types('int', 'uint')
  sleep = function(ms)
    while ms > 1000 do
      usleep(1000)
      ms = ms - 1000
    end
    usleep(1000 * ms)
  end
end 

print('hello')
sleep(500)  -- sleep 500 ms
print('world')

Я согласен с Джоном по поводу переноса функции сна.Вы также могли бы использовать эту обернутую функцию sleep для реализации функции pause в lua (которая просто переходила бы в спящий режим, а затем проверяла, не слишком ли часто менялось определенное условие).Альтернативой является использование крючков.

Я не совсем уверен, что вы имеете в виду, говоря о вашем третьем маркере (разве команды обычно не завершаются до выполнения следующей?) но с этим также могут помочь хуки.

Видишь:Вопрос:Как я могу чисто завершить поток Lua? для примера использования крючков.

Вы можете использовать:

os.execute("sleep 1") -- I think you can do every command of CMD using os.execute("command")

или вы можете использовать:

function wait(waitTime)
    timer = os.time()
    repeat until os.time() > timer + waitTime
end

wait(YourNumberHere)

Ты хочешь  win.Sleep(milliseconds), мне кажется.

Да, ты определенно не хочешь сидеть в напряженном ожидании, как ты описываешь.

Также легко использовать Alien в качестве оболочки libc / msvcrt:

> luarocks install alien

Затем из lua:

require 'alien'

if alien.platform == "windows" then
    -- untested!!
    libc = alien.load("msvcrt.dll")
else
    libc = alien.default
end 

usleep = libc.usleep
usleep:types('int', 'uint')

function sleep(ms)
    while ms > 1000 do
        usleep(1000)
        ms = ms - 1000
    end
    usleep(1000 * ms)
end

print('hello')
sleep(500)  -- sleep 500 ms
print('world')

Будьте внимательны , лектор:Я не пробовал это на MSWindows;Я даже не знаю, есть ли у msvcrt usleep()

Я начал с Lua, но затем обнаружил, что хочу видеть результаты вместо просто старой доброй командной строки flash.Поэтому я просто добавил следующую строку в свой файл, и вуаля, стандартный:

please press any key to continue...

os.execute("PAUSE")

Мой файл примера - это только распечатка, а затем сообщение о паузе, поэтому я уверен, что вам не нужно размещать это здесь.

Я не уверен в последствиях для процессора запуска процесса для полного скрипта.Однако остановка кода в середине процесса отладки может быть полезной.

Я полагаю, что для Windows вы можете использовать: os.execute("ping 1.1.1.1 /n 1 /w <time in milliseconds> >nul как простой таймер.(удалите "<>" при вставке времени в миллисекундах) (между остальной частью кода и >nul)

Это должно сработать:

    os.execute("PAUSE")
cy = function()
    local T = os.time()
        coroutine.yield(coroutine.resume(coroutine.create(function()
    end)))
    return os.time()-T
end
sleep = function(time)
    if not time or time == 0 then 
        time = cy()
    end
    local t = 0
    repeat
        local T = os.time()
        coroutine.yield(coroutine.resume(coroutine.create(function() end)))
        t = t + (os.time()-T)
    until t >= time
end
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top