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