Page 1 of 2
How to speed up a batch script
Posted: 22 Dec 2016 09:22
by Sounak@9434
Okay, keeping small thing small,
the title says it all (hey that rhymes
)
Anyway, I want to know how to speed up any batch file.
I know that the way of approaching the final motive matters a lot and each batch file is different(blah blah blah).
For my problem at first I searched in the internet and found some webpages but mostly they are telling about a specific script so I thought about asking here.
I want to know how to speed up any individual batch files. Like using this command instead of that. Or using this command in this way instead of that. Or using this tool instead of that etc.
Thanks in advance.
Re: How to speed up a batch script
Posted: 22 Dec 2016 10:51
by TSnake41
The speed of a batch script mostly depend of cmd.exe/csrss.exe, and a little of the batch script itself.
So, alternatives cmd.exe are very rare and rarely used but you can give a try to Dos9 :
viewtopic.php?f=3&t=5538 (if you can, build from source to get new features and fixes like pushd/popd)
Re: How to speed up a batch script
Posted: 22 Dec 2016 11:17
by aGerman
Batch is slow by design. The main reason is that half of the commands are external utilities. That means as soon as you call such a tool a new process has to be scheduled by the operating system. That takes a lot of time, especially if you call it umpteen times from within a loop. Whenever you have the choice use an internal command rather than an external. I wrote a little batch code that computes the commands outputted by the HELP command and displays whether they are internal functions of cmd.exe or external utilities.
Code: Select all
@echo off &setlocal EnableDelayedExpansion
set /a int=0, ext=0
for /f %%i in ('help^|findstr /rbc:"[A-Z][ABCDEFGHIJKLMNOPQRSTUVWXYZ]"') do (
for /f "tokens=1,2 delims=?" %%j in ("%%i.exe?%%i.com") do (
if "%%~$PATH:j%%~$PATH:k"=="" (
set /a int+=1
set "line=%%i "
echo !line:~,50! - internal
) else (
set /a ext+=1
echo %%i "%%~$PATH:j%%~$PATH:k"
)
)
)
echo(
echo internal %int%
echo external %ext%
pause>nul
We had some discussions in the past how to speed up the start of external tools. E.g. normally you would simply write FINDSTR to call C:\Windows\System32\findstr.exe. That means the process has to search the tool using two variables. 1) the directories saved in %PATH% and 2) the file extension saved in %PATHEXT%. That takes time. Instead you could empty these variables and call the tools by their full name.
Avoid using GOTO LABEL or CALL :LABEL if you can use a FOR (/L) loop instead. Labels have to be searched in the batch file. The order is top to down. It resumes searching at the top of the file if the end was reached without finding it. The longer the file the more time it takes.
But generally spoken: If you have a performance-critical task then don't use batch and prefer compiled languages over interpreted languages.
Steffen
Re: How to speed up a batch script
Posted: 22 Dec 2016 11:40
by ShadowThief
It really depends on your existing code; it's not like in VBA where you can say Application.ScreenUpdating=False and the whole thing speeds up by 90%.
Re: How to speed up a batch script
Posted: 26 Dec 2016 06:06
by Sounak@9434
I have used for (/l) in batch scripts to trigger loops and also somehow found a way to trigger endless loop.
Code: Select all
for /l %%a in (1,0,2) do (%command%)
but I was unable to break out of a for loop. Seems like goto label or exit /b does not works inside a for loop.
Any ideas anyone?
Re: How to speed up a batch script
Posted: 26 Dec 2016 06:50
by aGerman
You can simplify the infinite loop using an empty pair of parentheses.
However you still can't break the FOR /L loop. The only way is using EXIT which will quit the batch execution. You could run another process if you want to use this method (takes time to load the process etc...) or you have to use GOTO to perform the loop.
See this discussion:
viewtopic.php?t=2707Steffen
Re: How to speed up a batch script
Posted: 26 Dec 2016 07:11
by Sounak@9434
aGerman wrote:You can simplify the infinite loop using an empty pair of parentheses.
However you still can't break the FOR /L loop. The only way is using EXIT which will quit the batch execution. You could run another process if you want to use this method (takes time to load the process etc...) or you have to use GOTO to perform the loop.
See this discussion:
viewtopic.php?t=2707Steffen
Thanks Steffen but it does not actually solves my problem. I wanted a for loop because it's faster than goto but if it needs creating a seperate process it's definitely gonna be slower. Gotta find another way to achive this.
Re: How to speed up a batch script
Posted: 26 Dec 2016 07:21
by aGerman
Sounak@9434 wrote:Gotta find another way to achive this.
Good luck.
Re: How to speed up a batch script
Posted: 27 Dec 2016 09:41
by Sounak@9434
O.k. So after googling for hours I found that that there is no way to break an infinite for loop. Indirectly we can use a while macro.
But theoritically speaking which one should be faster on avarage Aacini's while macro or a goto :label loop?
Re: How to speed up a batch script
Posted: 27 Dec 2016 16:37
by aGerman
As I said, the larger the script the longer does it take to find the label. Just do some tests to figure out which is faster in your case.
Steffen
Re: How to speed up a batch script
Posted: 28 Dec 2016 05:29
by misol101
Sounak: Did you try the variant I used in some of the scripts I posted recently? The structure is:
Code: Select all
(set STOP=)
:LOOP
for /L %%1 in (1,1,300) do if not defined STOP (
...
(IF stopcondition set STOP=1)
)
IF not defined STOP goto LOOP
So as you can see the for loop itself is not infinite, But there is only one goto per 300 loops (or as many as you choose).
I think einstein1969 posted this first.
Re: How to speed up a batch script
Posted: 28 Dec 2016 06:02
by Sounak@9434
misol101 wrote:Sounak: Did you try the variant I used in some of the scripts I posted recently? The structure is:
Code: Select all
(set STOP=)
:LOOP
for /L %%1 in (1,1,300) do if not defined STOP (
...
(IF stopcondition set STOP=1)
)
IF not defined STOP goto LOOP
So as you can see the for loop itself is not infinite, But there is only one goto per 300 loops (or as many as you choose).
I think einstein1969 posted this first.
I have seen one made by jeb that uses goto:eof
I don't quite know if goto:eof is slower than regular goto label but surely your answer is useful.
Gonna give it a try too.
Re: How to speed up a batch script
Posted: 30 Dec 2016 04:34
by NunoLava1998
As of i know, a single batch command takes exactly 1 millisecond to execute.
This is proven when you do:
Code: Select all
echo 1
echo 2
echo 3
...
echo 999
echo 1000
that it takes 1 second to finish.
Re: How to speed up a batch script
Posted: 30 Dec 2016 05:25
by aGerman
NunoLava1998 wrote:As of i know, a single batch command takes exactly 1 millisecond to execute.
No. Try
>nul echo 1etc.
and try
cmd /c echo 1etc.
While the first should be faster because it doesn't output to the screen (and thus, doesn't invoke screen updating) the second is certainly a hundred times slower because the OS has to schedule a new process each.
Also 1ms may be true on your PC under certain conditions. It highly depends on the speed of your CPU, current CPU use, installed RAM, current memory availability, etc.
Steffen
Re: How to speed up a batch script
Posted: 30 Dec 2016 06:59
by misol101
Another little speedup trick is to clear out all or almost all unused environment variables. I found that all my scripts got a 5-10% speedup by doing this. I found this trick in a script by einstein1969. Just remember to call setlocal first, otherwise the variables are deleted from your actual cmd envioronment.
Code: Select all
setlocal
for /F "tokens=1 delims==" %%v in ('set') do set "%%v="
...
endlocal
Note that this will clear all variables, including the PATH. This works as long as you don't call any external programs, OR the external programs are either in your current folder OR they are called with absolute paths.
You could also easily keep one or more variables that you need, like PATH, by doing:
Code: Select all
for /F "tokens=1 delims==" %%v in ('set') do if /I not "%%v"=="PATH" set "%%v="