2015-04-19 16 views
7

C'è un modo per ritardare un file batch in meno di un secondo, ad esempio 10 millisecondi?ritarda un file batch in meno di un secondo?

ho cercato di scrivere questo:

ping localhost -n 1 -w 10 

Ma non ha funzionato

Qualcuno può aiutarmi?

+0

vedere http://stackoverflow.com/questions/166044/sleeping-in-a-batch-file – sashoalm

risposta

4

Qualche tempo fa I posted a method che fornisce tempi precisi con intervalli di ritardo da 15 millisecondi in poi. Questa è una copia dell'intero post.


Penso di aver ottenuto un ritardo di millisecondi con un tempo preciso quando il ritardo è piccolo. Ho usato una soluzione ibrida Batch-JScript con il metodo WScript.Sleep, ma per evitare il ritardo di caricamento della sezione JScript ogni volta che viene utilizzata, entrambe le parti devono essere attive contemporaneamente. Il processo JScript prende il ritardo in millisecondi, fa il ritardo e invia un segnale alla sezione Batch. Il processo batch invia il numero di millisecondi a JScript e attende il segnale. Il modo per ottenere questa comunicazione bidirezionale è tramite il metodo WshShwll.Exec di JScript che ha accesso ai flussi Stdin e Stdout di Batch.

@if (@CodeSection == @Batch) @then 


@echo off 
setlocal EnableDelayedExpansion 
if defined restart goto secondPart 

rem First part: execute JScript section, so it re-execute this Batch file 
set restart=true 
CScript //nologo //E:JScript "%~F0" "%~F0" 
goto :EOF 

:secondPart 

rem To do a delay, use: "echo #millisecs" followed by "set /P ="; use "echo 0" to end 
rem To display data in the screen, use: echo data > CON 
rem To read data from keyboard, use set /P "data=Prompt: " <CON> CON 

set runs=10 
For %%t in (5 10 15 20 30 50 100 250 500 1000) do (

    set time_idle_ms=%%t 
    (
    set t0=!time! 
    for /L %%p in (1,1,%runs%) do echo %%t& set /P = 
    set t1=!time! 
    ) 

    for /F "tokens=1-8 delims=:.," %%a in ("!t0: =0!:!t1: =0!") do (
     set /a "a=(((1%%e-1%%a)*60)+1%%f-1%%b)*6000+1%%g%%h-1%%c%%d, a+=(a>>31) & 8640000" 
    ) 

    set /a average_time=a*10/runs 
    echo(Input:!time_idle_ms! ms - Output: Average time !average_time! ms > CON 
) 

rem Send the signal to end JScript section 
echo 0 
goto :EOF 


@end 


// JScript section 

// Restart this Batch file with access to its Stdin and Stdout streams 
var WshShell = new ActiveXObject("WScript.Shell"); 
var BatchFile = WshShell.Exec('"'+WScript.Arguments(0)+'"'), delay; 

// Get delay, wait and send CR until delay equ 0 
while ((delay = BatchFile.Stdout.ReadLine()) != "0") { 
    WScript.Sleep(delay); 
    BatchFile.Stdin.WriteLine(); 
} 

uscita:

Input:5 ms - Output: Average time 15 ms 
Input:10 ms - Output: Average time 16 ms 
Input:15 ms - Output: Average time 15 ms 
Input:20 ms - Output: Average time 32 ms 
Input:30 ms - Output: Average time 31 ms 
Input:50 ms - Output: Average time 63 ms 
Input:100 ms - Output: Average time 109 ms 
Input:250 ms - Output: Average time 250 ms 
Input:500 ms - Output: Average time 500 ms 
Input:1000 ms - Output: Average time 1000 ms 

Un altro test in Windows 8.1 a 32 bit - 3.2 GHz

Input:5 ms - Output: Average time 14 ms 
Input:10 ms - Output: Average time 16 ms 
Input:15 ms - Output: Average time 15 ms 
Input:20 ms - Output: Average time 31 ms 
Input:30 ms - Output: Average time 32 ms 
Input:50 ms - Output: Average time 61 ms 
Input:100 ms - Output: Average time 110 ms 
Input:250 ms - Output: Average time 250 ms 
Input:500 ms - Output: Average time 501 ms 
Input:1000 ms - Output: Average time 1000 ms 

EDIT: pathping prova aggiunto

Proprio per completare questo argomento, Ho fatto un test di temporizzazione usando pathping e lo stesso codice usato per testare il mio metodo. Eccolo:

@echo off 
setlocal EnableDelayedExpansion 

set runs=10 
For %%t in (5 10 15 20 30 50 100 250 500 1000) do (

    set time_idle_ms=%%t 
    (
    set t0=!time! 
    for /L %%p in (1,1,%runs%) do pathping 127.0.0.1 -n -q 1 -p %%t >nul 
    set t1=!time! 
    ) 

    for /F "tokens=1-8 delims=:.," %%a in ("!t0: =0!:!t1: =0!") do (
     set /a "a=(((1%%e-1%%a)*60)+1%%f-1%%b)*6000+1%%g%%h-1%%c%%d, a+=(a>>31) & 8640000" 
    ) 

    set /a average_time=a*10/runs 
    echo(Input:!time_idle_ms! ms - Output: Average time !average_time! ms 

) 

Lo spettacolo risultato che pathping è non affidabile per i piccoli tempi di ritardo:

Input:5 ms - Output: Average time 48 ms 
Input:10 ms - Output: Average time 47 ms 
Input:15 ms - Output: Average time 47 ms 
Input:20 ms - Output: Average time 62 ms 
Input:30 ms - Output: Average time 63 ms 
Input:50 ms - Output: Average time 93 ms 
Input:100 ms - Output: Average time 141 ms 
Input:250 ms - Output: Average time 281 ms 
Input:500 ms - Output: Average time 532 ms 
Input:1000 ms - Output: Average time 1031 ms 
+0

Grazie mille per l'aiuto, ma non lo so Devo avere il tempo di presise in questo file batch. ma potrei usarlo in futuro quando dovrò essere presice, quindi comunque: D –

+0

Scusami? Penso che la tua richiesta sia stata molto chiara: "C'è un modo per ritardare un file batch in meno di un secondo, ad esempio 10 millisecondi?". Usando il 'pathping' puoi ritardare da 47 millisecondi con un errore medio del 97% negli ultimi 7 valori sotto un secondo usato nei test precedenti, ma con il mio metodo puoi ritardare un minimo di 15 millisecondi con un errore medio di soli 13 % negli stessi valori. Stai dicendo _ ora che "non deve avere un tempismo preciso" ??? ': (' – Aacini

+0

Approccio interessante.Tutti i normali batch IO non correlati al ritardo (stdin, stdout, stderr) devono essere reindirizzati a CON. Ciò potrebbe causare problemi, ad esempio, CLS non funziona correttamente quando viene reindirizzato a CON. che questo è guidato dagli eventi, quindi non consuma i cicli della CPU durante il sonno. – dbenham

1
pathping 127.0.0.1 -n -q 1 -p 100 >nul 

Here stata una discussione su una corretta attesa/ritardo nella milliseconds.According agli ultimi posti Pathping dovrebbe fare il lavoro per i millisecondi.

+0

grazie Inoltre, ha funzionato: D –

+0

Un test utilizzando 'pathping' dimostrano che è _not_ affidabile per le piccole tempi di ritardo. Vedi [la mia risposta] (http://stackoverflow.com/questions/29732878/delay-a-batch-file-in-under-a-second/29734001#29734001) – Aacini

1

Qui di seguito ho tre diverse soluzioni pura di script per la fornitura inferiori al secondo ritardi all'interno di un lotto script. Tutte queste soluzioni hanno un ritardo minimo che varia da macchina a macchina. Finché il ritardo minimo viene superato, ciascuno di essi è generalmente preciso entro 10 millisecondi.

Ho utilizzato l'imbracatura di test Aacini per verificare l'accuratezza di tutti e tre i metodi in modo che i risultati possano essere confrontati direttamente con i risultati.


Batch Macro

Questa soluzione lotto puro è molto semplice nel concetto. Ricevo l'ora corrente (con precisione di 1/100 di secondo), aggiungo il ritardo e aspetto quel nuovo tempo all'interno di un circuito chiuso.

Ho inserito questa logica in una tecnica di macro batch avanzata che è difficile da comprendere e sviluppare, ma facile da usare. Utilizzando una macro, non vi è alcun ritardo introdotto da CALL. Vedere Current batch macro syntax e historical development of batch macros se si desidera saperne di più sulla teoria delle macro batch e su come scriverne di proprie.

Questa soluzione batch pura ha il minimo ritardo minimo dei tre. Sulle due macchine che ho provato, il ritardo minimo variava da ~ 15 a ~ 30 msec. Questa macro supporta solo ritardi inferiori a 24 ore.

Lo svantaggio principale di questa macro è il consumo di risorse della CPU: ancoraggio di una singola CPU con un singolo core al 100% di utilizzo per tutto il ritardo.

@echo off 
setlocal disableDelayedExpansion 

::******** Define the @delay macro **************** 

:: define LF as a Line Feed (newline) character 
set ^"LF=^ 

^" Above empty line is required - do not remove 

:: define a newline with line continuation 
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^" 

set @delay=for %%# in (1 2) do if %%#==2 (%\n% 
    for /f "tokens=1-4 delims=:.," %%a in ("!time: =0!") do set /a "t1=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100, arg1/=10"%\n% 
    cmd /v:on /c for /l %%. in (^^^) do @for /f "tokens=1-4 delims=:.," %%a in ("^!time: =0^!"^^^) do @set /a "t2=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100,tDiff=t2-t1"^^^>nul^^^&(if ^^^^!tDiff^^^^! lss 0 set /a tDiff+=8640000^^^>nul^^^)^^^&if ^^^^!tDiff^^^^! geq ^^^^!arg1^^^^! exit%\n% 
    endlocal%\n% 
) else setlocal enableDelayedExpansion^&set arg1= 


::********** Demonstrate usage ******************** 
echo Delaying for 1.25 seconds ... 
%@delay% 1250 
echo done. 
echo(


::*********** Testing accuracy ******************** 
setlocal enableDelayedExpansion 
echo Testing accuracy: 
set runs=10 
for %%t in (10 20 30 40 50 70 100 250 500 1000) do (

    (
    set t0=!time! 
    for /l %%p in (1,1,%runs%) do %@delay% %%t 
    set t1=!time! 
) 

    for /f "tokens=1-8 delims=:.," %%a in ("!t0: =0!:!t1: =0!") do (
    set /a "a=(((1%%e-1%%a)*60)+1%%f-1%%b)*6000+1%%g%%h-1%%c%%d, a+=(a>>31) & 8640000" 
) 

    set /a average_time=a*10/runs 
    echo(Input:%%t ms - Output: Average time !average_time! ms 
) 

- I risultati dei campioni -

Delaying for 1.25 seconds ... 
done. 

Testing accuracy: 
Input:10 ms - Output: Average time 14 ms 
Input:20 ms - Output: Average time 20 ms 
Input:30 ms - Output: Average time 30 ms 
Input:40 ms - Output: Average time 40 ms 
Input:50 ms - Output: Average time 50 ms 
Input:70 ms - Output: Average time 70 ms 
Input:100 ms - Output: Average time 100 ms 
Input:250 ms - Output: Average time 250 ms 
Input:500 ms - Output: Average time 500 ms 
Input:1000 ms - Output: Average time 1000 ms 


SLEEP.BAT - ibrida JScript/batch (Locale Agnostic)

Questa è la mia soluzione preferita. CHIAMA il mio programma di utilità SLEEP.BAT, passando il ritardo desiderato, più l'attuale %time% al momento della CHIAMATA. Lo script batch chiama JScript incorporato nello stesso file, che sottrae il tempo CALL dall'ora corrente per determinare quanto tempo è già trascorso e quindi sottrae questo valore dal tempo di ritardo per capire per quanto tempo lo script deve dormire. Questa soluzione utilizza il metodo WScript.sleep(), che è guidato dagli eventi e non consuma risorse della CPU.

Lo script batch fornirà il proprio valore %time% se non viene inoltrato, ma la precisione potrebbe risentirne un po 'a causa del tempo necessario per CHIAMARE l'utilità.

Ci vuole un tempo significativo per inizializzare CSCRIPT, quindi il ritardo minimo è più lungo della soluzione macro. Sulle mie due macchine, il ritardo minimo variava da ~ 30 a ~ 55 msec.

SLEEP.BAT dovrebbe funzionare su qualsiasi computer Windows, indipendentemente da come le impostazioni internazionali visualizzano la data e l'ora. L'unico problema che ho con questa utilità è che può dare il ritardo sbagliato se chiamato l'istante prima del passaggio dall'ora standard all'ora legale, o viceversa.

SLEEP.BAT

@if (@X)==(@Y) @end /* harmless hybrid line that begins a JScript comment 
@goto :batch 
::: 
:::SLEEP.BAT msec [%time%] 
:::SLEEP.BAT /? 
::: 
::: Suspend processing for msec milliseconds. The optional %time% argument 
::: can be added to improve timing accuracy. If called within a FOR loop, 
::: then !time! should be used instead, after enabling delayed expansion. 
::: 
::: There is a startup time for SLEEP.BAT that limits the shortest delay 
::: possible. The startup time varies from machine to machine. Delays longer 
::: than the minimum are usually accurate to within 10 msec if the %time% 
::: argument is provided. One exception is when SLEEP.BAT is called the 
::: instant before changing from standard to daylight savings time, in which 
::: case the delay is extended by the startup time. The other exception occurs 
::: when changing from daylight savings to standard, in which case the delay 
::: never exceeds the startup time. 
::: 
::: A single /? argument displays this help. 
::: 
::: SLEEP.BAT Version 1.0 - written by Dave Benham 
::: 

============= :Batch portion =========== 
@echo off 
if "%~1" equ "/?" (
    for /f "tokens=* delims=:" %%A in ('findstr "^:::" "%~f0"') do @echo(%%A 
    exit /b 0 
) else cscript //E:JScript //nologo "%~f0" %* %time% 
exit /b 

============ JScript portion ==========*/ 
try { 
    var arg2 = WScript.Arguments.Item(1).split(/[:.,]/); 
    var start = new Date(); 
    if (start.getHours()<Number(arg2[0])) start.setDate(start.getDate()-1); 
    start.setHours(Number(arg2[0]), 
        Number(arg2[1]), 
        Number(arg2[2]), 
        Number(arg2[3])*10 
       ); 
    var delay = Number(WScript.Arguments.Item(0)); 
    var adjustedDelay = delay - ((new Date())-start); 
    if (adjustedDelay>0) WScript.sleep((adjustedDelay>delay) ? delay : adjustedDelay); 
    WScript.Quit(0); 
} catch(e) { 
    WScript.Stderr.WriteLine("SLEEP.BAT - Invalid call"); 
    WScript.Quit(1); 
} 

test harness e dimostrazione di utilizzo

@echo off 
setlocal enableDelayedExpansion 
set runs=10 
for %%t in (20 30 40 50 70 100 250 500 1000) do (

    (
    set t0=!time! 
    for /l %%p in (1,1,%runs%) do call sleep %%t !time! 
    set t1=!time! 
) 

    for /f "tokens=1-8 delims=:.," %%a in ("!t0: =0!:!t1: =0!") do (
    set /a "a=(((1%%e-1%%a)*60)+1%%f-1%%b)*6000+1%%g%%h-1%%c%%d, a+=(a>>31) & 8640000" 
) 

    set /a average_time=a*10/runs 
    echo(Input:%%t ms - Output: Average time !average_time! ms 
) 

- Esempio di output -

Input:20 ms - Output: Average time 56 ms 
Input:30 ms - Output: Average time 55 ms 
Input:40 ms - Output: Average time 54 ms 
Input:50 ms - Output: Average time 56 ms 
Input:70 ms - Output: Average time 71 ms 
Input:100 ms - Output: Average time 100 ms 
Input:250 ms - Output: Average time 253 ms 
Input:500 ms - Output: Average time 501 ms 
Input:1000 ms - Output: Average time 1001 ms 


LocaleSleep.bat - JScript ibrida/Lotto (Loc ale dipendenti)

Questo è quasi identico a SLEEP.BAT, tranne che passa in "%date% %time%" anziché "%time%. Il vantaggio è che non ha più problemi con il passaggio tra l'ora standard e l'ora legale. Il principale svantaggio è che è dipendente dalle impostazioni internazionali. Funziona solo se %date% viene analizzato correttamente dal metodo parse() dell'oggetto Date. So che questo dovrebbe funzionare sulla maggior parte delle macchine degli Stati Uniti, oltre ad altri. Le varianti possono essere scritte per supportare altre impostazioni locali, ma ognuna di esse potrebbe essere dipendente dalle impostazioni internazionali.

LocaleSleep.bat

@if (@X)==(@Y) @end /* harmless hybrid line that begins a JScript comment 
@goto :batch 
::: 
:::LocaleSleep.bat msec ["%date% %time%"] 
:::LocaleSleep.bat /? 
::: 
::: Suspend processing for msec milliseconds. The optional "%date% %time%" 
::: argument can be added to improve timing accuracy. If called within a 
::: FOR loop, then "!date! !time!" should be used instead, after enabling 
::: delayed expansion. 
::: 
::: This utility is locale specific. It only works properly if %date% is in 
::: a format that is parsed properly by the Date object parse() method. 
::: 
::: There is a startup time for SLEEP.BAT that limits the shortest delay 
::: possible. The startup time varies from machine to machine. Delays longer 
::: than the minimum are usually accurate to within 10 msec if the 
::: "%date% %time%" argument is provided. 
::: 
::: A single /? argument displays this help. 
::: 
::: LocaleSleep.bat Version 1.0 - written by Dave Benham 
::: 

============= :Batch portion =========== 
@echo off 
if "%~1" equ "/?" (
    for /f "tokens=* delims=:" %%A in ('findstr "^:::" "%~f0"') do @echo(%%A 
    exit /b 0 
) else cscript //E:JScript //nologo "%~f0" %* "%date% %time%" 
exit /b 

============ JScript portion ==========*/ 
try { 
    var arg2 = WScript.Arguments.Item(1); 
    var delay = Number(WScript.Arguments.Item(0)) - ((new Date())-(new Date(arg2.slice(0,-3))).setMilliseconds(Number(arg2.slice(-2))*10)); 
    if (delay>0) WScript.sleep(delay); 
    WScript.Quit(0); 
} catch(e) { 
    WScript.Stderr.WriteLine("localeSleep.bat - Invalid call"); 
    WScript.Quit(1); 
} 

test harness e dimostrazione di utilizzo

@echo off 
setlocal enableDelayedExpansion 
set runs=10 
for %%t in (20 30 40 50 70 100 250 500 1000) do (

    (
    set t0=!time! 
    for /l %%p in (1,1,%runs%) do call localeSleep %%t "!date! !time!" 
    set t1=!time! 
) 

    for /f "tokens=1-8 delims=:.," %%a in ("!t0: =0!:!t1: =0!") do (
    set /a "a=(((1%%e-1%%a)*60)+1%%f-1%%b)*6000+1%%g%%h-1%%c%%d, a+=(a>>31) & 8640000" 
) 

    set /a average_time=a*10/runs 
    echo(Input:%%t ms - Output: Average time !average_time! ms 
) 

I risultati sono praticamente identiche a SLEEP.BAT

0

C'è una parte del Sleep.exe Windows Server 2003 Resource Kit Tools dove è possibile specificare il tempo di spegnimento in millisecondi:

λ sleep /? 
Usage: sleep  time-to-sleep-in-seconds 
     sleep [-m] time-to-sleep-in-milliseconds 
     sleep [-c] commited-memory ratio (1%-100%) 
Problemi correlati