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

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

  •  06-07-2019
  •  | 
  •  

Question

Je n'arrive pas à comprendre comment faire en sorte que Lua fasse des astuces de chronométrage courantes, telles que

.
  • sleep - arrête toute action sur le fil

  • pause / wait - ne passez pas à la suivante commande, mais autoriser un autre code dans la application pour continuer

  • Bloc
  • - ne passez pas à la commande suivante tant que le le courant retourne

Et j'ai lu qu'un

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

consomme du temps processeur.

Des suggestions? Y a-t-il un appel d'API qui me manque?

MISE À JOUR : J'ai écrit cette question il y a longtemps en essayant de faire en sorte que WOW Lua rejoue les actions selon un calendrier (par exemple, attendez, attendez 1 seconde, dansez, attendez 2 secondes, assoyez-vous. Sans pause, ils se produisent presque tous au cours du même quart de seconde.) Comme il s’est avéré, WOW a volontairement désactivé presque tout ce qui permet d’agir sur une horloge, car cela risquerait de casser le jeu ou d’activer des robots. pour recréer une horloge une fois qu'elle a été retirée, je devrais 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 un tas d'événements courants, comme le déplacement de la souris, puis, dans le gestionnaire de traitement 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é.

Était-ce utile?

La solution

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 sans interruptions spéciales. Voici:

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

Autres conseils

[J'allais publier ceci sous forme de commentaire sur Le message de John Cromartie , mais ne s'est pas rendu compte 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, faire des appels de shell coûte cher. 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, dans le menu principal, effectuez les opérations suivantes:

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

S'il vous arrive d'utiliser LuaSocket dans votre projet, installé et ne vous dérange pas de l’utiliser, vous pouvez utiliser le socket.sleep (time) fonction qui dort pendant une durée donnée (en secondes).

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

Je dois ajouter que la fonction prend en charge les fractions de seconde en tant que paramètre, ce qui signifie que socket.sleep (0.5) dormira une demi-seconde. Il utilise Sleep () sous Windows et nanosleep () a> ailleurs, vous pouvez donc rencontrer des problèmes d’exactitude dans Windows lorsque temps devient trop bas.

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")

(cela bloquera)

Il est évident que cela ne fonctionne que sur les systèmes d'exploitation pour lesquels "quot1 sommeil" " est une commande valide, par exemple Unix, mais pas Windows.

pour Windows, vous pouvez le faire:

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

Fonction de veille - Utilisation: sleep (1) - dort pendant 1 seconde

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

Fonction de pause - Utilisation: pause () - met en pause et attend la touche Retour

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

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

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

Pure Lua utilise uniquement les éléments de la norme ANSI C. Le module lposix contient une grande partie de ce dont vous avez besoin pour faire plus de choses systémiques.

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 dans Lua, vous avez le texte suivant:

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

Je suis d'accord avec John pour intégrer la fonction de sommeil. Vous pouvez également utiliser cette fonction de veille intégrée pour implémenter une fonction de pause dans lua (qui se contenterait de dormir puis de vérifier si une condition particulière avait 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 l'exécution de la suivante?), mais les crochets peuvent également vous aider.

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

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)

Vous voulez & nbsp; win.Sleep (millisecondes) , merci.

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

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

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

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, 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 CPU 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.

Je crois que pour Windows, vous pouvez utiliser: os.execute ("ping 1.1.1.1 / n 1 / w", en millisecondes > > nul , sous la forme d'une minuterie simple. (supprimez les "< >" lors de l'insertion du temps en millisecondes) (il y a un espace entre le reste du code et > nul )

Cela devrait fonctionner:

    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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top