Board logo

标题: 【共同参与】批处理代码,算法的效率分析 [打印本页]

作者: plp626    时间: 2009-10-7 05:43     标题: 【共同参与】批处理代码,算法的效率分析

提前告知大家:发此帖子为了大家共同完成接力任务,【请看二楼的帖子】,
希望关注此帖的fans能继续接力任务


cmd基本命令耗时预备知识

测试方法:
  1. set aa=%time%&for /l %%a in (1 1 10000)do echo .......
  2. call etime %aa% %time%
复制代码
  1. set aa=%time%&for /l %%a in (1 1 10000)do set a=0
  2. call etime %aa% %time%
复制代码
将时间差进行比较,{etime代码看此帖http://bbs.bathome.net/thread-4701-1-1.html

我们计最基本的set var=... ; [这里...一般不超过30字节]为一个时间单位

我初略试了试发现如下:
预处理耗时:【0.55】
一个if 判断语句 或者 for %%a 或for /f ... ("string")   相当于0.5~0.6个时间单位

set /a 耗时:【1.1~1.7】
set/a a=... 含一个等号,相当于1.1~1.7 时间单位
set/a a=... 多个等号,相当于 0.96*n个 时间单位

二次预处理算术运算赋值 耗时 【2】
一个call set/a ... 含一个等号 相当于 2 个时间单位

echo 命令耗时         【9.5】
echo ... [这里...一般不超过50字节]

变量作用域设定耗时:【12】
一对setlocal  endlocal 执行一次 相当于 12 时间单位

set/p=... <nul 耗时 【29】
set/p=... <nul  [这里...一般不超过50字节]

跳转耗时:【72 】
仅仅一个goto 标签或者call :标签 相当于72个时间单位!!!


二次预处理赋值耗时:【108】
一个call set 相当于 108个时间单位

call echo 耗时 【120】
call echo ... [这里...一般不超过50字节]

三方命令耗时 【2500左右】
非cmd内置命令的外部工具或者for /f ... %%a in ('commond')do  相当于2450个时间单位

其他的大家继续补充,或者写个代码做批量测试,此工作还是蛮有意义的, 以后分析算法的效率一定很有用
现在我拿折半法求字符串长度的代码分析耗费的时间单位
  1. @echo off&setlocal enabledelayedexpansion
  2. set "str=afdjg do men contgfirfmck     song putint"
  3. :binsearch //by 随风
  4. set /a max=8190,min=0 // 【2.2】
  5. for /l %%a in (1,1,14) do ( // 【0.55】
  6.      set /a "num=(max+min)/2" //【1.15*14】
  7.      for /f "delims=" %%b in ("!num!") do if "!str:~%%b!" equ "" (set /a max=num) else set /a min=num //【0.55*14+(0.6+1.1)*14】
  8. )
  9. if "!str:~%num%!" neq "" set /a num+=1 //【0.55+1.1】
  10. echo 经计算字符串str共有%num%个字符
  11. pause>nul
复制代码
可以看出这个binsearch耗费 33.8 个时间单位,效率不错

--------------------------------------
-----------------------------

代码中有
findstr
find  
sort
more
*.vbs
*.exe
*.com
for /f  ... ('commond')do ...
goto
call :label   // 对于过于复杂的代码子过程能提高可读性,缩短编写时间,这个就单另说了,但是绝大多数使用call,goto命令的代码【可以说接近百分之百】都可以转换为for语句

其中之一者,切记不要让他进入循环

findstr
find  
sort
more
*.vbs
*.exe
*.com
for /f  ... ('commond')do ...
其中之一,其执行次数不要超过两次

否则,你的代码效率将慢如驴。。。

[ 本帖最后由 plp626 于 2009-10-10 17:53 编辑 ]
作者: plp626    时间: 2009-10-7 05:50

忘了说一点:
cmd是从磁盘的bat文件以"整行为单位"读取到内存然后预处理解释,执行完后在再继续从磁盘。。。

这和js,vbs,等解释语言是不同的,

楼上的测试代码是整行的,实际代码,大家并不总是把多行代码用括号扩起来或者用&来连接多个命令,所以就成了多行,cmd会从文件中读取好多次到内存中,所以上面的结果代表了cmd最快的解释效率;
----------------------------------------------------------------------------------------------------------------
还有好多命令的耗费时间单位 需要大家测试啊
接力棒开始了

del
ren
md
rd
dir
attrib
shift
pushd  + popd
break
for /r
for /d
生产临时文件
变量截取%%!! 混用等

[ 本帖最后由 plp626 于 2009-10-7 13:40 编辑 ]
作者: Batcher    时间: 2009-10-7 09:15

cmd是从磁盘的bat文件以"整行为单位"读取到内存然后预处理解释,执行完后在再继续从磁盘。。。

有什么证据来证明吗?
作者: zqz0012005    时间: 2009-10-7 09:23

以前的分析
CMD是逐行读取bat内容,并根据偏移量开始下一次的读取。
比如以下内容:
@echo off
pause
pause
第一次暂停时,已经读取过的内容是@echo off\r\npause\r\n,偏移量是18个字节,cmd接下来会从第19个字节开始读取,即下一行的pause。此时如果在第一个pause后面加上“  dir”(2个空格+dir),则从19个字节开始的内容变成了dir\r\n,碰到回车换行,于是执行dir命令。再接着才会执行后面的pause。

上面是在脚本运行过程中改变脚本文件的内容。

[ 本帖最后由 zqz0012005 于 2009-10-7 09:25 编辑 ]
作者: Batcher    时间: 2009-10-7 09:29     标题: 回复 4楼 的帖子

能否讲解一下所谓的“读取”是从哪里读到哪里呢?
硬盘?硬盘的缓存?虚拟内存?物理内存?
作者: zqz0012005    时间: 2009-10-7 09:44     标题: 回复 5楼 的帖子

应该是从硬盘上的文件读取到内存(文本放入物理内存一般都够吧)
作者: defanive    时间: 2009-10-7 11:38

的确,是执行到哪行就读文件的哪行,不会预先读到内存中。。。
批处理运行时修改文件本身可以看到端倪。。。
作者: plp626    时间: 2009-10-7 13:38

将多行代码 用括号括起来
比如
  1. (
  2. echo fdfd
  3. echo dfdfd
  4. echo fdfd
  5. )
复制代码

要比
  1. echo fdfd
  2. echo dfdfd
  3. echo fdfd
复制代码

执行的效率略高
cmd是从磁盘的bat文件以"整行为单位"读取到内存然后预处理解释,执行完后在再继续从磁盘。。。

我给一个很简结充分的证据
  1. (
  2. pause
  3. pause
  4. )
复制代码

当第一次暂停时,打开文件把第二个pause语句删掉,然后保存,回到控制台,按任键,还是暂停
如果把那对括号去掉,就不会有上面的现象

还有,在执行过程中,如果对所在bat文件进行改名,会导致cmd命令行提示
找不到批处理文件
导致后面的语句都不会得到执行

这在其他脚本中是没有的现象
作者: netbenton    时间: 2009-10-7 13:48

  1. @echo off
  2. echo 自动增涨的批处理
  3. set "abc=echo %%abc%%>>%0&call echo 当前大小:%%~z0字节&pause"
  4. %abc%
复制代码

作者: zqz0012005    时间: 2009-10-7 13:55

不错。
这个既是bat的缺点,也是它的优点,可以在执行过程中改变自身,并动态执行(重载?呵呵),比较灵活。而且有些用法很适合把bat自身作为临时文件/数据文件,运行时根据改变的内容决定执行步骤。

相比其他脚本和大多数命令而言,bat是比较另类的。for 也是全部读取文件到内存再处理。我还没注意到其他哪个程序处理文件是分部分逐次读取的。
作者: plp626    时间: 2009-10-7 14:05

关于cmd的解释机制, 大家若讨论,希望另开一帖,
现在大家的回复严重跑题了了。。。。。。。。。。。!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
作者: zqz0012005    时间: 2009-10-7 14:42

还有管道耗时,&&、|| 与 if errorlevel 的效率比较。
重定向到文件,这个也许可以归结到文件写操作类命令。
读、写碰盘文件的命令可能普通耗时较多,尤其是写。

讨论命令机制的效率的一篇文:批处理中for /f 解析命令输出的效率
http://www.bathome.net/viewthread.php?tid=3591

运行外部命令,可能还有从path环境变量中找到命令程序的耗时。
直接运行一般文件而由系统自己运行关联程序来打开它,可能还要先搜索注册表的耗时。
类似的,运行外部命令时可能还要读取组策略、注册表等系统数据库的所有相关的配置,如映象劫持之类的。
这些算是命令的启动时间吧。
至于一个具体命令,可能还要到哪里读什么文件、信息之类的,再加上正式执行过程,最后可能又要更新什么文件(三方?),加起来算是命令的运行时间。
命令运行的总时间应该要包括这两个时间。




欢迎光临 批处理之家 (http://bbs.bathome.net/) Powered by Discuz! 7.2