标题: [转贴] 浅谈批处理脚本的编写 - 1.效率篇 [打印本页]
作者: HAT 时间: 2011-12-17 13:55 标题: 浅谈批处理脚本的编写 - 1.效率篇
1.效率篇
代码效率的提升往往由算法决定,曾发过专贴(浅谈提高代码效率的编写习惯:http://tieba.baidu.com/p/1187281687),但是以实例为主,并没有太多的文字说明,现在归纳一下:
影响代码效率的主要有几点:
1.1 外部命令、goto、call 的调用次数
这是众所周知的,这里只列个提纲,就不详加说明了
1.1.1 外部命令启动慢、运行快,所以不宜频繁启动
1.1.2 goto、call、exit 都是比较耗时的(相对于 for 构建的循环)
1.1.3 管道至少开启两个新进程(内部命令或语块将启用 cmd 解析执行),不解释
1.1.4 for /f 从命令获取输入时必然启用 cmd 进程,不解释
1.2 变量尽量少
批处理中的变量是以变量表的形式存储,每次读取时从头读到符合条件的变量位置,所以我们所设定的变量越多、在表中位置越靠后,效率越低。
值得注意的是,变量不仅仅受 set 影响,setlocal 的本质也是开辟一个新的变量表作为本地化操作下的临时变量环境,所以每次使用 setlocal 都会增加将当前的变量表所占用的空间,但因为旧的变量表处于“隐藏”状态,所以对效率没有明显的影响
1.3 算法思想(重点)
这是我今天在效率方面想要论述的核心内容,撇开五花八门的技巧不谈,优化算法的时候应该遵循两个准则:
1.3.1 将循环次数由指数级变为算术级
指数级运算是以乘法为基础的,算术级运算则是以加法为基础的(还不懂就看代码吧),随着运算量的增加,指数级算法的实际运算量将远高于算术级算法
【code1】- @echo off&setlocal enabledelayedexpansion
- (for /f "delims=" %%a in (a.txt) do (
- set /a a+=1,b=0
- echo %%a
- rem 输出 a.txt 内容
- for /f "delims=" %%b in (b.txt) do (
- set /a b+=1
- if !a!==!b! echo %%b
- rem 逐行对比行号,当相等时输出 b.txt 内容
- )
- ))>合并ab文本.txt
- ::循环次数为 a.txt*b.txt 的行数
复制代码
【code2】- @echo off&setlocal enabledelayedexpansion
- for %%a in (a b) do (
- for /f "delims=" %%b in (%%a) do set /a "%%a+=10001"&echo !%%a:~-4!%%a:%%b
- )>>tmp.txt
- ::将ab两文件补位,使对行的前缀均为 [行号][文件名],这样排序时行号相同的内容将被输出为上下行
- sort tmp.txt /o tmp.txt
- ::排序tmp.txt,并输出到原文件
- (for /f "tokesn=1* delims=:" %%a in (tmp.txt) do echo %%b)>合并ab文本.txt
- ::循环次数为 (a.txt+b.txt)*2 的行数
复制代码
再比如:
【code1】- ::解约瑟夫环问题,详细介绍请自行百度。
- @echo off&setlocal enabledelayedexpansion&set "str= "
- echo %time%
- for /l %%a in (1,1,29) do set "str=!str!%%a "
- for /l %%a in () do (
- for %%a in (!str!) do (
- set /a "n=(n+1)%%3"
- if !n!==0 set "str=!str: %%a = !"
- )
- for /f "tokens=1,2" %%a in ("!str!") do if "%%b"=="" echo 最后剩下的是%%a号&echo !time!&pause>nul&exit
- )
- ::修改自 batman 的代码,使用 for 嵌套逐个去除复合条件的项,运算量为 !29(就是 1*2*3*4 一直到 29)
复制代码
【code2】- @echo off
- set /a n=29,k=1,m=3,s=0
- for /l %%a in (2,1,%n%) do set /a s=(s+m)%%%%a
- set /a x=(s+k)%%n
- if %x% equ 0 (set x=%n%)
- echo 最后剩下是:%x%
- pause
- ::修改自 inittab 的公式法方案,运算量为 29
复制代码
初中学过,前者的函数图象是u形曲线,后者则是稳定的直线,也就是算法的复杂度下降了
1.3.2 将加法思路变为减法思路
加法思路是每次都将结果处理成所需的格式再输出
减法思路是先得出大概的结果,再慢慢修正
【code1】- (for %%a in (*.txt) do findstr /v ". $" "%%a"&&echo 文件 %%a 为空)>空文件列表.txt
- ::逐个判断文件是否为空,为空则输出文件名。
复制代码
【code2】- (for /f "delims=" %%a in ('findstr /mv ". $" *.txt') do echo 文件 %%a 为空)>空文件列表.txt
- ::一次性输出空文件名,再将结果修正为所需的格式
复制代码
类似的例子还有:
【code1】- for %%a in (*.bat) do ren "%%a" "%%~na.txt"
- ::用 for 逐个重命名 bat 文件为txt,这是典型的加法思路
复制代码
【code2】- ren *.bat *.txt
- ::一次性重命名所有bat文件为txt,这是减法思路中一次成型的特例
复制代码
遇到比较复杂的情况时,先整出个大样子,再一点一点修正,往往比从头到尾精雕细琢一轮来完成要快很多
1.4 影响环境的操作尽量少
包括变量写入、句柄的重定向、除 nul 之外所有设备的输出(文件是 file 设备)等等都是比较耗时的,这个也在旧帖中亦有较详细的论述,在此略过不谈。
转自:http://tieba.baidu.com/p/1326823919
作者: cjiabing 时间: 2011-12-20 23:43
呵呵,效率我就不谈了,看看各位有什么补充的。
作者: HAT 时间: 2011-12-20 23:57
扩展阅读:
提高批处理代码效率的常用技巧及方案
http://www.bathome.net/thread-4831-1-1.html
http://www.bathome.net/thread-4482-1-1.html
欢迎光临 批处理之家 (http://bathome.net./) |
Powered by Discuz! 7.2 |