luaスクリプトを数秒間待機/一時停止/スリープ/ブロックさせる最も簡単な方法は?
-
06-07-2019 - |
質問
次のような一般的なタイミングトリックを行うためにluaを取得する方法がわかりません
-
sleep-スレッドのすべてのアクションを停止
-
一時停止/待機-次へ進まない コマンド、ただし他のコードを許可 続行するアプリケーション
-
block-次のコマンドに進まないでください 現在のものが戻る
そして、私はそれを読みました
while os.clock()<time_point do
--nothing
end
CPU時間を使い果たします。
提案はありますか?欠落しているAPI呼び出しはありますか?
更新:ずっと前に、WOW Luaにスケジュールに従ってアクションを再生させようとしてこの質問を書きました(つまり、立ち、1秒待ち、ダンス、2秒待ち、座っています。これらはほぼすべて同じ四半期に発生します。) WOWは、ゲームを中断したりボットを有効にしたりする可能性があるため、クロックでアクションを実行できるほとんどすべてを意図的に無効にしました。取り去られたら時計を再作成します。作業配列を作成し(アクションと実行時間を含む)、マウスの移動などの一般的なイベントのイベントハンドラーを登録するなど、おかしなことをする必要があります。次に、偶数ハンドラーで、時間が来たアクションを処理します。イベントハンドラーは実際には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
他のヒント
[ John Cromartieの投稿ですが、コメントでフォーマットを使用できないことに気づきませんでした。]
同意します。 os.execute()を使用してシェルにドロップすることは間違いなく機能しますが、一般的にシェル呼び出しを行うにはコストがかかります。一部の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;
}
次に、主に、次のことを行います:
lua_pushcfunction(L, lua_sleep);
lua_setglobal(L, "sleep");
where <!> quot; L <!> quot;あなたのlua_Stateです。次に、C / C ++から呼び出されたLuaスクリプトで、次を呼び出して関数を使用できます。
sleep(1000) -- Sleeps for one second
プロジェクトで LuaSocket を使用する場合、または単に使用する場合インストールして使用しても構いません。 socket.sleep(time)
関数は、一定時間(秒単位)スリープします。
これはWindowsとUnixの両方で機能し、追加のモジュールをコンパイルする必要はありません。
関数がパラメーターとして小数秒をサポートすることを追加する必要があります。つまり、 socket.sleep(0.5)
は0.5秒スリープします。 Sleep()を使用します。
(Windows)および nanosleep()
他の場所にあるため、 time
が低すぎるとWindowsの精度に問題が生じる可能性があります。
CPUを消費せずに純粋なLuaでそれを行うことはできませんが、簡単で移植性のない方法があります:
os.execute(&quot; sleep 1&quot;)
(ブロックします)
明らかに、これは「スリープ1」がサポートされているオペレーティングシステムでのみ機能します。 Unixなどの有効なコマンドですが、Windowsではありません。
これを行うことができるウィンドウの場合:
os.execute("CHOICE /n /d:y /c:yn /t:5")
スリープ機能-使用法: sleep(1)-1秒間スリープします
local clock = os.clock
function sleep(n) -- seconds
local t0 = clock()
while clock() - t0 <= n do
end
end
一時停止関数-使用法: pause()-一時停止してReturnキーを待つ
function pause()
io.stdin:read'*l'
end
希望、これがあなたが必要なものです! :D-ジョーDF
ホストシステムのスリープ関数をCでラップする単純な関数を実装します。
Pure LuaはANSI標準Cにあるもののみを使用します。LuizFiguereidoの lposixモジュールには、より体系的なことを行うために必要なものの多くが含まれています。
Luaで処理を停止し、アプリケーションの実行を続ける2番目のリクエストである一時停止/待機には、コルーチンが必要です。次のような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')
スリープ機能のラッピングに関してジョンに同意します。 このラップされたスリープ関数を使用して、luaに一時停止関数を実装することもできます(スリープしてから、特定の条件が頻繁に変更されるかどうかを確認します)。別の方法は、フックを使用することです。
3番目の箇条書きの意味が正確にはわかりません(通常、次のコマンドが実行される前にコマンドが完了しないのですか?)
参照: 質問: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)
&nbsp; win.Sleep(milliseconds)
、methinksが必要です。
ええ、あなたは間違いなくあなたが説明するような忙しい待ちをしたくありません。
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から始めましたが、古き良きコマンドラインフラッシュだけではなく、結果を見たいと思いました。そのため、次の行をファイルに追加しましたが、これが標準です。
please press any key to continue...
os.execute("PAUSE")
私のサンプルファイルは印刷物であり、一時停止の文ですので、ここに投稿する必要はありません。
完全なスクリプトでプロセスを実行することのCPUへの影響はわかりません。ただし、デバッグの途中でコードを停止すると便利な場合があります。
使用できるウィンドウには os.execute(&quot; ping 1.1.1.1 / n 1 / w&lt; time in milliseconds&gt;&gt; nul
を単純なタイマーとして使用します。
(ミリ秒単位で時間を挿入するときに&quot;&lt;&gt;&quot;を削除します)(コードの残りと&gt; 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