web-dev-qa-db-fra.com

Meilleure façon de faire en sorte que le script Lua attende/pause/veille/bloque quelques secondes

Je n'arrive pas à comprendre comment faire en sorte que Lua fasse des tours de chronométrage courants, tels que

  • sleep - arrête toute action sur le fil 

  • pause/wait - n'entrez pas dans la prochaine commande mais laissez un autre code de l'application continuer 

  • block - ne passe pas à la commande suivante avant le retour de la commande courante

Et j'ai lu qu'un 

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

mange du temps CPU.

Aucune suggestion? Y a-t-il un appel d'API qui me manque?

UPDATE: J'ai écrit cette question il y a longtemps en essayant de demander à WOW Lua de rejouer des actions selon un calendrier (par exemple, rester debout, attendre 1 seconde, danser, attendre 2 secondes, s'asseoir. Sans pause, elles se produisent presque toutes dans le même quart de seconde.) Comme il s’est avéré, WOW a volontairement désactivé pratiquement tout ce qui permet d’agir sur une horloge, car cela pourrait interrompre le jeu ou permettre aux robots de jouer. Je pensais que pour recréer une horloge une fois qu'elle avait été enlevée, je devais faire quelque chose de fou, comme créer un tableau de travail (avec une action et une heure d'exécution), puis enregistrer un gestionnaire d'événements sur plusieurs événements courants. , comme le déplacement de la souris, puis dans le gestionnaire pair, traite toute action dont le temps est venu. Le gestionnaire d'événements ne se produirait pas toutes les X millisecondes, mais s'il se produisait toutes les 2 à 100 ms, cela serait suffisamment proche. Malheureusement, je n'ai jamais essayé.

30
MatthewMartin

Cela ne devient pas plus facile que cela. Le sommeil peut être implémenté dans votre FLTK ou autre, mais cela couvre toutes les meilleures façons de faire le type de sommeil standard du système sans interruption d’événement spéciale. Voir:

-- 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
4
Fluff

[J'allais publier ceci sous forme de commentaire sur John Cromartie's post, mais je ne savais pas que vous ne pouviez pas utiliser la mise en forme dans un commentaire.]

Je suis d'accord. Le déposer dans un shell avec os.execute () fonctionnera certainement, mais en général, les appels au shell sont coûteux. Envelopper du code C sera beaucoup plus rapide au moment de l'exécution. En C/C++ sur un système Linux, vous pouvez utiliser:

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;
}

Ensuite, en gros, faites: 

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

où "L" est votre lua_State. Ensuite, dans votre script Lua appelé à partir de C/C++, vous pouvez utiliser votre fonction en appelant:

sleep(1000) -- Sleeps for one second
20
zslayton

Si vous utilisez LuaSocket dans votre projet, ou si vous l'avez simplement installé et que cela ne vous dérange pas, vous pouvez utiliser la fonction socket.sleep(time) qui dort pendant une durée donnée (en secondes) .

Cela fonctionne à la fois sous Windows et Unix, et vous n'avez pas à compiler de modules supplémentaires.

Je devrais ajouter que la fonction prend en charge la fraction de seconde en tant que paramètre, c’est-à-dire que socket.sleep(0.5) dormira une demi-seconde. Il utilise Sleep() sous Windows et nanosleep() ailleurs. Vous risquez donc d’être confronté à des problèmes d’exactitude de Windows lorsque time devient trop faible.

18
Michal Kottman

Vous ne pouvez pas le faire en Lua pur sans manger de processeur, mais il existe un moyen simple et non portable:

os.execute ("sleep 1")

(ça va bloquer)

Évidemment, cela ne fonctionne que sur les systèmes d'exploitation pour lesquels "sleep 1" est une commande valide, par exemple Unix, mais pas Windows.

10
Kknd

pour les fenêtres, vous pouvez faire ceci:

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

Fonction de veille - Utilisation: sleep(1) -- sleeps for 1 second

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

Fonction de pause - Utilisation: pause() -- pause and waits for the Return key

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

espérons que c'est ce dont vous aviez besoin! : D - Joe DF

7
Joe DF

Pure Lua utilise uniquement ce qui est dans la norme ANSI C. Le module lposix module de Luiz Figuereido contient une grande partie de ce dont vous avez besoin pour faire des choses plus systématiques.

3
Norman Ramsey

Je mettrais en œuvre une fonction simple pour envelopper la fonction de sommeil du système hôte en C.

3
John Cromartie
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')
3
avo

Pour la deuxième demande, pause/attente, lorsque vous arrêtez le traitement dans Lua et continuez à exécuter votre application, vous avez besoin de coroutines. Vous vous retrouvez avec un code C comme celui-ci:

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

et à Lua, vous avez:

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)
3
BMitch

Vous pouvez utiliser:

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

ou vous pouvez utiliser:

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

wait(YourNumberHere)
2
grmmhp

Je suis d’accord avec John sur l’enveloppement de la fonction de veille .. Vous pouvez également utiliser cette fonction de veille enveloppée pour implémenter une fonction de pause dans Lua (qui dormirait simplement puis vérifierait si une condition particulière a changé de temps en temps). Une alternative consiste à utiliser des crochets. 

Je ne suis pas tout à fait sûr de ce que vous entendez par votre troisième puce (les commandes ne sont-elles généralement pas terminées avant que la suivante ne soit exécutée?), Mais les crochets peuvent également vous aider.

Voir: Question: Comment puis-je terminer un fil Lua proprement? pour un exemple d'utilisation de crochets.

2
CiscoIPPhone

Vous voulez win.Sleep(milliseconds), il me semble.

Ouais, vous ne voulez certainement pas faire une attente occupée comme vous le décrivez.

1
chaos

Il est également facile d’utiliser Alien comme wrapper libc/msvcrt:

> luarocks install alien

Puis de 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')

Avertissement du lecteur: Je n'ai pas essayé ceci sous MSWindows; Je ne sais même pas si msvcrt a un usleep ()

1
DSA

J'ai commencé avec Lua mais, ensuite, j'ai découvert que je voulais voir les résultats plutôt que simplement le bon vieux flash en ligne de commande. Donc, je viens d'ajouter la ligne suivante à mon fichier et hop, la norme:

please press any key to continue...

os.execute("PAUSE")

Mon exemple de fichier n’est qu’une impression, puis une pause, donc je suis sûr que vous n’avez pas besoin de la publier ici.

Je ne suis pas sûr des implications en termes de processeur d'un processus en cours d'exécution pour un script complet. Cependant, arrêter le code en cours de débogage pourrait être utile.

1
Ian

Je crois que pour Windows, vous pouvez utiliser: os.execute("ping 1.1.1.1 /n 1 /w <time in milliseconds> >nul comme un simple timer . (Supprimez le "<>" lors de l'insertion de l'heure en millisecondes) (il y a un espace entre le reste du code et >nul

1
Cruz Jean
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
0
Descaii

Cela devrait fonctionner:

    os.execute("PAUSE")
0
Anonymous