Meilleure façon de faire en sorte que le script Lua attende / pause / veille / bloque pendant quelques secondes?
-
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é.
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