让lua脚本等待/暂停/睡眠/阻塞几秒钟的最简单方法?

Posted

技术标签:

【中文标题】让lua脚本等待/暂停/睡眠/阻塞几秒钟的最简单方法?【英文标题】:Easiest way to make lua script wait/pause/sleep/block for a few seconds? 【发布时间】:2010-11-05 06:45:11 【问题描述】:

我不知道如何让 lua 做任何常见的计时技巧,例如

睡眠 - 停止线程上的所有操作

暂停/等待 - 不要继续下一个 命令,但允许在 申请继续

block - 不要继续下一个命令,直到 当前返回

我已经读过一个

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

占用 CPU 时间。

有什么建议吗?有没有我遗漏的 API 调用?

更新:我很久以前写过这个问题,试图让 WOW Lua 按计划重播动作(即站立,等待 1 秒,跳舞,等待 2 秒,坐下。没有停顿,这些几乎都发生在同一个季度秒内。)As it turned out WOW had purposely disabled pretty much everything that allows doing action on a clock because it could break the game or enable bots. 我想在时钟被拿走后重新创建一个时钟,我不得不做一些疯狂的事情,比如创建一个工作数组(有一个动作和执行时间)然后在一堆常见的事件上注册一个事件处理程序,比如鼠标移动,然后在偶数处理程序中,处理任何时间到的动作。事件处理程序实际上不会每 X 毫秒发生一次,但如果它每 2-100 毫秒发生一次,它就足够接近了。遗憾的是我从未尝试过。

【问题讨论】:

【参考方案1】:

[我打算将此作为评论发布在 John Cromartie's 帖子上,但没有意识到您不能在评论中使用格式。]

我同意。使用 os.execute() 将其放入 shell 肯定会起作用,但通常进行 shell 调用很昂贵。在运行时包装一些 C 代码会快得多。在 Linux 系统上的 C/C++ 中,您可以使用:

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;

然后,在 main 中,做:

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

其中“L”是你的 lua_State。然后,在从 C/C++ 调用的 Lua 脚本中,您可以通过调用来使用您的函数:

sleep(1000) -- Sleeps for one second

【讨论】:

【参考方案2】:

如果您碰巧在您的项目中使用了LuaSocket,或者只是安装了它并且不介意使用它,您可以使用socket.sleep(time) 函数,它会休眠给定的时间(以秒为单位)。

这适用于 Windows 和 Unix,您不必编译额外的模块。

我应该补充一点,该函数支持小数秒作为参数,即socket.sleep(0.5) 将休眠半秒。它在 Windows 上使用 Sleep() 并在其他地方使用 nanosleep(),因此当 time 变得太低时,您可能会遇到 Windows 准确性问题。

【讨论】:

【参考方案3】:

在不吃CPU的情况下你不能在纯Lua中做到这一点,但是有一个简单的、非便携的方法:

os.execute("睡眠 1")

(它会阻塞)

显然,这仅适用于“sleep 1”是有效命令的操作系统,例如 Unix,但不适用于 Windows。

【讨论】:

请注意,在某些可以使用此功能的系统(例如 OS X)上,这不会导致 os.clock() 前进,因为不会消耗 CPU 时间。【参考方案4】:

睡眠功能 - 用法: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

希望,这就是您所需要的! :D - 乔 DF

【讨论】:

【参考方案5】:

对于 Windows,您可以这样做:

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

【讨论】:

【参考方案6】:

没有比这更容易的了。睡眠可能会在您的 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:typesret="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

【讨论】:

在寻找简单的解决方案时,我越来越讨厌 lua ...【参考方案7】:

对于第二个请求,暂停/等待,您在 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)

【讨论】:

【参考方案8】:

我将实现一个简单的函数来将主机系统的睡眠函数包装在 C 中。

【讨论】:

【参考方案9】:

Pure Lua 仅使用 ANSI 标准 C 中的内容。Luiz Figuereido 的 lposix module 包含您需要做更多系统性事情的大部分内容。

【讨论】:

【参考方案10】:
require 'alien'

if alien.platform == "windows" then
  kernel32 = alien.load("kernel32.dll")
  sleep = kernel32.Sleep
  sleep:typesret="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')

【讨论】:

【参考方案11】:

我同意约翰关于包装睡眠功能的观点。 你也可以使用这个封装的 sleep 函数在 lua 中实现一个 pause 函数(它会简单地 sleep 然后检查某个条件是否经常发生变化)。另一种方法是使用钩子。

我不太清楚你的第三个要点是什么意思(命令通常不会在下一个执行之前完成吗?)但是钩子也可以帮助解决这个问题。

见: Question: How can I end a Lua thread cleanly? 举个使用钩子的例子。

【讨论】:

【参考方案12】:

你可以使用:

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)

【讨论】:

【参考方案13】:

你想要win.Sleep(milliseconds),我想。

是的,你绝对不想像你描述的那样忙着等待。

【讨论】:

【参考方案14】:

使用 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()

【讨论】:

【参考方案15】:

我从 Lua 开始,但后来我发现我想查看结果,而不仅仅是旧的命令行 flash。所以我只是在我的文件中添加了以下行,嘿,标准:

please press any key to continue...

os.execute("PAUSE")

我的示例文件只是一个打印,然后是一个暂停语句,所以我相信你不需要在这里发布。

我不确定为完整脚本运行进程对 CPU 的影响。但是,在调试过程中停止代码中间流可能会很有用。

【讨论】:

【参考方案16】:

我相信对于 Windows,您可以使用:os.execute("ping 1.1.1.1 /n 1 /w &lt;time in milliseconds&gt; &gt;nul 作为一个简单的计时器。 (插入时间以毫秒为单位时去掉“”)(其余代码与&gt;nul之间有一个空格)

【讨论】:

【参考方案17】:

这应该可行:

    os.execute("PAUSE")

【讨论】:

【参考方案18】:
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

【讨论】:

【参考方案19】:

你可以这样做:

function Sleep(seconds)
    local endTime = os.time() + seconds
    while os.time() < endTime do
    end
end
print("This is printed first!")
Sleep(5)
print("This is printed 5 seconds later!")

【讨论】:

以上是关于让lua脚本等待/暂停/睡眠/阻塞几秒钟的最简单方法?的主要内容,如果未能解决你的问题,请参考以下文章

Lua微秒睡眠

我可以使用等待而不是睡眠吗? [复制]

你如何告诉一个函数在 Kotlin 中等待几秒钟?

Windows批处理:睡眠[重复]

在不阻塞 UI 执行的情况下等待几秒钟

在java一个方法中,如何让一行代码执行完毕以后等待几秒钟后再执行另一行代码 主要 是一个方法中