[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[原创] 讨论:批处理运行效率浅谈

批处理运行效率浅谈
  大家在写批处理时,除了要考虑代码的通用性,易读性,及简洁以外,效率也是一个应该要考虑的问题。
那么批处理在什么情况下会影响效率呢?
以下是自己写代码的一些经验,欢迎大家跟帖讨论,发表自己的看法。。。
1、call 命令  若在代码使用次数超过50次左右,(大概)会影响效率
2、goto 命令  若在代码使用次数超过50次左右,(大概)会影响效率
3、findstr find dir 这几个命令,若是在一个代码中使用5次,有时甚至是2次,都会明显拖慢速度。
所以在写代码时,应尽量避开这样的用法。
call
  1. ::假设a.txt内容有50行。测试以下两个代码的速度
  2. @echo off
  3. for /f %%a in (a.txt) do (
  4.    set var=%%a
  5.    set /a n=2
  6.    call echo %%var:~!n!,1%%
  7. )
  8. pause
复制代码
  1. ::假设a.txt内容有50行。
  2. @echo off
  3. for /f %%a in (a.txt) do (
  4.    set var=%%a
  5.    set /a n=2
  6.    echo !var:~2,1!
  7. )
  8. pause
复制代码
findstr
  1. ::假设a.txt内容有50行。测试以下两个代码的速度
  2. @echo off
  3. for /f %%a in (a.txt) do (
  4.    echo %%a|findstr a
  5. )
  6. pause
复制代码
  1. ::假设a.txt内容有50行
  2. @echo off
  3. for /f %%a in ('findstr "a" a.txt') do echo %%a
  4. pause
复制代码
dir
  1. @echo off
  2. ::假设当前目录文件比较多。
  3. for /f "delims=" %%a in ('dir/b/s/a-d') do (
  4.    for /f "delims=" %%i in ('dir/b "%%a"') do (
  5.       echo %%i
  6. ))
  7. pause
复制代码
技术问题请到论坛发帖求助!

遍历目录文件的时候,for /r应该比for /f效率高吧。
我帮忙写的代码不需要付钱。如果一定要给,请在微信群或QQ群发给大家吧。
【微信公众号、微信群、QQ群】http://bbs.bathome.net/thread-3473-1-1.html
【支持批处理之家,加入VIP会员!】http://bbs.bathome.net/thread-67716-1-1.html

TOP

我来说两句吧

&&关于代码运行的效率,本人以前也在各种回贴中多次提及。写出来的代码效率不高
这是新手们经常出现的问题,这是正常的,高手们也都是从这个阶段走过来的。新手们
刚开始自己写代码时应重在于解决问题上,只要代码能够解决问题,这就是成功,关于
代码的简洁和效率问题,只有在不断的学习和练习中去慢慢解决它。当然,新手们在编
写代码时还应多听听老手们的意见。下面本人就结合个人的经验来谈谈如何提高代码运
行时的效率:
  1、call语式是批处理中经常使用的语式,在代码中合理地运用call能大大减少代码,
但,就如随风兄所说的一样,如果在代码中调用call的次数过多的话,代码的效率就会明
显降低,同时还有call的变量延迟功能在反复赋值的情况下也会降低代码效率,下面就以
两段代码来说明下这个问题(call语式的例子随风兄已给出,在这里就不再举例了):
  1. @echo off&setlocal enabledelayedexpansion
  2. set "t=%time%"
  3. for /l %%i in (1,1,10000) do (
  4.     set "str=%%i"
  5.     echo !str!
  6. )
  7. echo 开始时间%t%
  8. echo 结束时间%time%
  9. pause>nul
复制代码
  1. @echo off
  2. set "t=%time%"
  3. for /l %%i in (1,1,10000) do (
  4.     set "str=%%i"
  5.     call,echo %%str%%
  6. )
  7. echo 开始时间%t%
  8. echo 结束时间%time%
  9. pause>nul
复制代码
  分别运行这两段代码你会发现第二段代码运行的时间远远长于第一段代码,这就是
因为反复使用了10000次call延迟的原因。
  2、新手们在刚刚接触for循环特别是多个for循环的嵌套时也经常会出现效率上的大
问题,而这个效率问题就是总循环次数是+还是*的问题,可能这样说大家不是很明白,
下面一样结合代码来说明吧:
  有a.txt、b.txt,两文本行数相同(假设为均有100行)现在要求通过批处理将两文本
相同行数的内容合并输出并在中间以一个#来连接
  1. @echo off&setlocal enabledelayedexpansion
  2. set "t=%time%"
  3. for /f "delims=" %%a in (a.txt) do ([
  4.   set /a n+=1,m=0
  5.     for /f "delims=" %%i in (b.txt) do (
  6.         set /a m+=1
  7.         if !n! equ !m! echo %%a#%%i
  8.     )
  9. )
  10. echo 开始时间%t%
  11. echo 结束时间%time%
  12. pause>nul
复制代码
  1. @echo off
  2. set "t=%time%"&set "n=-1"
  3. :begin
  4. set /a n+=1
  5. if %n% equ 0 (
  6.    set "sk="
  7.    ) else (
  8.    set "sk=skip=%n%"
  9. )
  10. for /f "%sk% delims=" %%i in (a.txt) do set /p=%%i#<NUL&GOTO next
  11. :next
  12. for /f "%sk% delims=" %%i in (b.txt) do set /p=%%i<NUL&ECHO.&GOTO begin
  13. echo 开始时间%t%
  14. echo 结束时间%time%
  15. pause>nul
复制代码
  
  大家可以看出第二段代码比起第一段代码要复杂,那么运行效率呢,实际上第二段
代码的效率是远高于第一段代码的,为什么呢?我们就来分析一下吧:第一段代码先是
从a.txt中读取第一行内容然后将n值加1并将m值归0,然后进行b.txt开始逐行读取并将每
次将m值加1如遇到n值和m值相同时就输出a.txt中的第一行和b.txt中的这一行(实际也
就是b.txt中的第一行),然后再读取a.txt中的第二行再重复上述比对和输出,如此当整个
循环运行完成,第二个for循环就足足整个比对了b.txt100次,也就是比对了10000行的内
容;而第二段代码是先从a.txt中读取第一行并输出然后跳到b.txt读取和输出第一行内容
再返回begin标签,再用skip来忽略a.txt的第一行读取输出第二行后又跳到b.txt同样用skip
忽略掉b.txt的第一行读取和输出b.txt的第二行再次返回begin标签,如此一直到所有的内
容被输出,所以其总共的读取次数是200,这也是最少的比对次数,100+100和100*100
相信大家都知道谁快谁慢了吧。
  3、还有一个不但是新手同样老手也会常出现的效率问题,那就是在设计代码方案时
存在的问题,本来在一个代码不需要进行比对和返回而设计了比对和返回,以代码示之:
  如随机生成9000个不同的0-10000内的数
  1. @echo off
  2. set "t=%time%"
  3. :begin
  4. set /a a=%random%%%10000+1
  5. if not defined _%a% (
  6.    set /p=%a% <NUL
  7.    set /a n+=1&set "_%a%=a"
  8.    ) else (
  9.   goto begin
  10. )
  11. if %n% neq 9000 goto begin
  12. echo.&echo 开始时间%t%
  13. echo 结束时间%time%
  14. pause>nul
复制代码
  1. @echo off&setlocal enabledelayedexpansion
  2. set "t=%time%"
  3. for /l %%i in (0,1,10000) do set "_!random!!random!!random!!random!=%%i"
  4. for /f "tokens=2 delims==" %%i in ('set _') do (
  5.      set /p=%%i <NUL
  6.      set /a n+=1
  7.      if !n! equ 9000 goto end
  8. )
  9. :end
  10. echo.&echo 开始时间%t%
  11. echo 结束时间%time%
  12. pause>nul
复制代码
  
  第一段代码将会慢得让你的机器都不能忍受,就是因为其中不可计数的比对和返回
次数大大降低了运行的效率,当然在所取数和基数相差值较大的情况下这种方案还是可
以采用的。    
  好了,说了这么一大通无非就是请大家在设计和编写代码时多多考虑效率方面的问
题,如有解释得不透或有误的地方还望大家指出了。

[ 本帖最后由 batman 于 2008-10-7 16:21 编辑 ]
***共同提高***

TOP

工作量多时用setlocal延迟,少时则可以用call延迟(简洁代码),总之用最适合的代码做最适合的事情吧。
心绪平和,眼藏静谧。

TOP

  关注代码的执行效率,应该是我们应该高度重视的事情,应该放在简洁性之前。我认为,衡量一个代码质量的高低,首先要看这个代码的设计方案是否合理,其次是具体代码是否正确,再然后,就是代码效率如何,然后,再关注代码的简洁性,最后,再看兼容性或通用性如何,如果再提高一个层次,还得关注易用性如何,如果要对这些因素的优先级别做一个排序的话,应该是这样的:方案的合理性>代码的准确性>代码的执行效率>代码的简洁性>代码的通用性>代码的易用性。

  对于代码的执行效率问题,前面各位已经有了较为详细的介绍,并且还用代码加以解释,已经比较透彻了,时间关系,我暂时不再详细展开予以补充,在这里只是指出顶楼的一个小错误:随风在考察findstr的执行效率的时候,用了 echo %%a|findstr a 这个代码,这个代码其实并不能很好地解释findstr的执行效率问题,真正影响这段代码执行效率的,是管道符号|,大量的输入输出操作才是系统执行效率的瓶颈所在,要想提高效率,应该尽量不要频繁使用管道操作符,如果实在无法避免输入输出操作,建议用临时文件方案替代。
尺有所短寸有所长,学好批处理没商量;
考虑问题复杂化,解决问题简洁化。

心在天山,身老沧州。

TOP

原帖由 namejm 于 2008-10-7 14:24 发表
  真正影响这段代码执行效率的,是管道符号|,大量的输入输出操作才是系统执行效率的瓶颈所在 ...

管道符号也许也是一个问题,(本人暂时还没遇到过这方面的问题)也许是我顶楼的例子不恰当。
但频繁使用 findstr 应该绝对是影响效率的原因。
请分别测试以下两句代码便知。
  1. @echo off
  2. for /l %%a in (1 1 30) do findstr . a.txt
  3. for /l %%a in (1 1 30) do type a.txt
  4. pause
复制代码
技术问题请到论坛发帖求助!

TOP

  findstr确实会拖慢速度,推测原因是这样的:因为findstr的开关很多,在执行findstr的时候,需要检测每个开关的打开状态,而type没有开关,不用在检测开关状态上花费时间,所以费时不多。
尺有所短寸有所长,学好批处理没商量;
考虑问题复杂化,解决问题简洁化。

心在天山,身老沧州。

TOP

findstr是什么意思,新手,请大家多多指教

TOP

坛子群雄聚集啊,这贴精华当之无愧。

TOP

呵呵。都是斑竹,超级斑竹,管理员!!呵呵~~经典的讨论

TOP

一个成功的bat是能完成任务
一个高质量的bat是用最少的时间

我现在在向第一个目标前进
目的,学习批处理

TOP

回复 8楼 的帖子

帮助里面解释的很详细:
findstr /?
我帮忙写的代码不需要付钱。如果一定要给,请在微信群或QQ群发给大家吧。
【微信公众号、微信群、QQ群】http://bbs.bathome.net/thread-3473-1-1.html
【支持批处理之家,加入VIP会员!】http://bbs.bathome.net/thread-67716-1-1.html

TOP

受教了。在论坛里确实学到很多。代码的效率和各种语言一样应该都是很重要的。

TOP

返回列表