[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖
本帖最后由 plp626 于 2011-4-23 08:25 编辑
  1. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  2. :: 这个代码可以根据设定,比较出以下因素:
  3. :: 1、 垃圾变量数
  4. :: 2、 set赋值方式(是否带/a参数)
  5. :: 3、 待赋值变量是否已经包含在垃圾变量集合内
  6. :: 对赋值操作耗时的影响
  7. :::::::::::::::::::::::::::::::::::::::::::::::::::::::
  8. @echo off&setlocal EnableDelayedExpansion
  9. :: loop值不能过小,便于比较出差异
  10. set/a loop=6000
  11. set/a p=500
  12. set/a num=loop/p
  13. :: 测试变量为已储存变量数的5百分之一
  14. :: 能看出均匀增加,但测试结果和loop值的千分之一有直接关系
  15. set "pre1=_"      :: 垃圾变量前缀
  16. set "pre2=_"      :: 待赋值变量前缀
  17. set "med=set "  :: 赋值方式
  18. ======================%测试开始%=========================
  19. if "%pre1%"=="%pre2%" (
  20. echo “垃圾变量名”中【含有】待赋值变量的测试
  21. ) else (
  22. echo “垃圾变量名”中【不含有】待赋值变量的测试
  23. )
  24. :: 生成“垃圾变量”
  25. for /l %%a in (1,1,%loop%) do set %pre1%%%a=1
  26. :: 测试赋值耗时变化
  27. for /l %%z in (1 1 %num%)do (set/a tp=tt,tt=0
  28. set t1=!time!
  29. for /l %%a in (1 1 %loop%)do %med% %pre2%%%z=1
  30. set t2=!time!
  31. set/a tt=1!t2:~-5,2!!t2:~-2!-1!t1:~-5,2!!t1:~-2!,tt+="-6000*(tt>>31)"
  32. set /a cc=tt-tp
  33. echo  执行%loop%次%med% %pre2%%%z=1耗时:!tt!,阶差:!cc!
  34. )
  35. pause
复制代码

TOP

昨晚的测试代码含有call,运行后比较不出来,但把语句放在一个复合语句里却可以,

原因分析
1、垃圾变量设定太少;
2、call的堆栈也占用空间;

TOP

  1. @echo off
  2. :: loop值不能过小(大于2000即可),便于看出差异
  3. set/a loop=6000
  4. set/a p=500
  5. set/a num=loop/p
  6. :: 测试变量为已储存变量数的5百分之一,
  7. :: 能看出均匀增加,但测试结果和loop值的千分之一有直接关系
  8. echo “垃圾变量名”中【含有】待赋值变量的测试
  9. for /l %%a in (1,1,%loop%) do set _%%a=1
  10. setlocal EnableDelayedExpansion
  11. for /l %%z in (1 1 %num%)do (set/a tp=tt,tt=0
  12. set t1=!time!
  13. for /l %%a in (1 1 %loop%)do set _%%z=1
  14. set t2=!time!
  15. set/a tt=1!t2:~-5,2!!t2:~-2!-1!t1:~-5,2!!t1:~-2!,tt+="-6000*(tt>>31)"
  16. set /a cc=tt-tp
  17. echo  执行%loop%次set _%%z=1耗时:!tt!,阶差:!cc!
  18. )
  19. pause
复制代码
运行结果:
  1. “垃圾变量名”中【含有】待赋值变量的测试
  2. 执行6000次set _1=1耗时:125,阶差:125
  3. 执行6000次set _2=1耗时:148,阶差:23
  4. 执行6000次set _3=1耗时:183,阶差:35
  5. 执行6000次set _4=1耗时:215,阶差:32
  6. 执行6000次set _5=1耗时:252,阶差:37
  7. 执行6000次set _6=1耗时:286,阶差:34
  8. 执行6000次set _7=1耗时:289,阶差:3
  9. 执行6000次set _8=1耗时:290,阶差:1
  10. 执行6000次set _9=1耗时:291,阶差:1
  11. 执行6000次set _10=1耗时:122,阶差:-169
  12. 执行6000次set _11=1耗时:125,阶差:3
  13. 执行6000次set _12=1耗时:128,阶差:3
复制代码

TOP

为什么要用 set /a 呢?set /a 能代表单纯的变量读写吗?
hanyeguxing 发表于 2011-4-23 03:04


你考虑的也挺全面的呵。。。,

TOP

本帖最后由 hanyeguxing 于 2011-4-23 09:03 编辑

环境变量名是按字符逐字顺序排列的,例如2排在17的后面,下面两图是系统环境变量在内存中的存储
.


.
为什么要用 set /a 呢?set /a 能代表单纯的变量读写吗?使用 set a=%#10000% 这样的形式更合适吧?
测试代码:
  1. @echo off
  2. rem set n=10000 1 39999
  3. rem set n=39999 -1 10000
  4. echo %time%开始%n%
  5. for /l %%a in (%n%) do set #%%a=1
  6. echo %time%赋值完成
  7. for /l %%a in (%n%) do set a=%#10000%
  8. echo %time%第一批完成
  9. for /l %%a in (%n%) do set a=%#39999%
  10. echo %time%第二批完成
  11. pause
复制代码
第一次set n=39999 -1 10000倒序两个差距千分之1.3,第二次set n=10000 1 39999正序(没关第一个cmd)差距千分之2.17
.

.
怎么就没得出有那么大的差距呢?
.

.
命令解释器在读写变量时是按照变量名逐个顺序匹配的的。
1,变量名顺序,以上图本地化变量组为例。
2,特例。特殊情况也是存在的,例如变量 %COMSPEC% 就单独排在整个变量的最前面。这个破规则从MS-DOS时代就开始了,因为那个时候他是核心,到今天的系统依然作如此保留。
3,两个变量之间由 00 空字符分隔
4,逐字匹配。先以变量名的第一个字符在本地变量存储空间顺序匹配变量名的第一个字符;如果匹配到,则继续在以第一字符开头的区间内继续匹配第二个字符,如果没有就直接返回为空...以此类推,而不是遍历整个变量存储空间。
这样做的好处是大大加快变量的读写速度。
如果变量存储的顺序是按照赋值的先后排列的话,那么每次读取都需要完整遍历一次整个本地变量空间,那是很没效率的,微软也不会这么设计。
附件: 您需要登录才可以下载或查看附件。没有帐号?注册
1

评分人数

寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

本帖最后由 batman 于 2011-4-23 02:06 编辑

上面的三次数据测试基本可以证明:

    cmd对变量的储存和读取是遵循其默认的序列机制的,即cmd会将当前设置的变量+=号+值的所有字符放在

一起进行正序排列(ansi编码序列),排前的字符放入内存中靠前的地址,而将排后的字符放入内存中靠后的地

址。然后在后面的读取寻址中则是一个遍历的过程,即首先查找比对存入最前地址中的字符,如果相符则取出

,如不相符则对下一个地址进行比对,一直到找到完全的匹配。也就是说当内存中储存的变量越多时,而要取

出后面地址中储存的变量所要消耗的时间越长(如在前面地址中则无明显时间的变化),也就是说当出现大量

变量时,对于排序在前的变量在程序中的运算影响并不是很大,而对排序在后的变量在程序中的运算这个影响

将是巨大的。由此可见cmd无论从哪个方面都逃不开其根本的序列机制(字符的ansi编码序列)。
***共同提高***

TOP

本帖最后由 batman 于 2011-4-23 01:38 编辑

接着测试(又是一次头大的等待)
代码:
  1. @echo off&setlocal enabledelayedexpansion
  2. for /l %%a in (1,1,10000) do set /a "_%%a=1"
  3. for /l %%a in (1,1,9) do (
  4.     set "num="
  5.     for /l %%b in (1,1,4) do (
  6.         set "num=!num!%%a"
  7.         for %%a in (!num!) do (
  8.             set "t=!time!"
  9.             for /l %%b in (1,1,10000) do set /a _%%a+=1
  10.             set "t1=!time!"&set "a="
  11.             if "!t:~,2!" lss "!t1:~,2!" set "a=+24"
  12.             set /a ".%%a=(!t1:~,2!-!t:~,2!!a!)*360000+(1!t1:~3,2!%%100-1!t:~3,2!%%100)*6000+(1!t1:~6,2!%%100-1!t:~6,2!%%100)*100+(1!t1:~-2!%%100-1!t:~-2!%%100)"
  13.        )
  14.     )
  15. )
  16. set .
  17. pause>nul
复制代码
运行结果:
  1. .1=393
  2. .11=440
  3. .111=409
  4. .1111=411
  5. .2=525
  6. .22=559
  7. .222=566
  8. .2222=562
  9. .3=657
  10. .33=711
  11. .333=717
  12. .3333=722
  13. .4=796
  14. .44=866
  15. .444=877
  16. .4444=876
  17. .5=928
  18. .55=1019
  19. .555=1036
  20. .5555=1028
  21. .6=1065
  22. .66=1166
  23. .666=1181
  24. .6666=1183
  25. .7=1191
  26. .77=1317
  27. .777=1336
  28. .7777=1342
  29. .8=1353
  30. .88=1483
  31. .888=1490
  32. .8888=1507
  33. .9=1476
  34. .99=1633
  35. .999=1655
  36. .9999=1656
复制代码
***共同提高***

TOP

懒人关注: 等各位阶段性的研究成果, 支持!

TOP

再测试(这下等得我。。。。)
代码:
  1. @echo off&setlocal enabledelayedexpansion
  2. for /l %%a in (1,1,10000) do set /a "_%%a=1"
  3. for /l %%a in (1,1,100) do (
  4.     set "t=!time!"
  5.     for /l %%b in (1,1,10000) do set /a _%%a+=1
  6.     set "t1=!time!"&set "a="
  7.     if "!t:~,2!" lss "!t1:~,2!" set "a=+24"
  8.     set /a ".%%a=(!t1:~,2!-!t:~,2!!a!)*360000+(1!t1:~3,2!%%100-1!t:~3,2!%%100)*6000+(1!t1:~6,2!%%100-1!t:~6,2!%%100)*100+(1!t1:~-2!%%100-1!t:~-2!%%100)"
  9. )
  10. set .
  11. pause>nul
复制代码
运行结果:
  1. .1=389
  2. .10=390
  3. .100=413
  4. .11=406
  5. .12=426
  6. .13=439
  7. .14=466
  8. .15=473
  9. .16=502
  10. .17=514
  11. .18=520
  12. .19=546
  13. .2=528
  14. .20=520
  15. .21=537
  16. .22=555
  17. .23=577
  18. .24=590
  19. .25=606
  20. .26=625
  21. .27=647
  22. .28=652
  23. .29=677
  24. .3=654
  25. .30=657
  26. .31=678
  27. .32=697
  28. .33=717
  29. .34=736
  30. .35=738
  31. .36=758
  32. .37=786
  33. .38=799
  34. .39=810
  35. .4=782
  36. .40=791
  37. .41=804
  38. .42=823
  39. .43=841
  40. .44=855
  41. .45=872
  42. .46=887
  43. .47=906
  44. .48=926
  45. .49=943
  46. .5=918
  47. .50=918
  48. .51=961
  49. .52=969
  50. .53=978
  51. .54=992
  52. .55=1011
  53. .56=1018
  54. .57=1033
  55. .58=1059
  56. .59=1067
  57. .6=1050
  58. .60=1052
  59. .61=1071
  60. .62=1085
  61. .63=1107
  62. .64=1118
  63. .65=1136
  64. .66=1154
  65. .67=1176
  66. .68=1200
  67. .69=1216
  68. .7=1179
  69. .70=1192
  70. .71=1206
  71. .72=1224
  72. .73=1242
  73. .74=1254
  74. .75=1280
  75. .76=1302
  76. .77=1322
  77. .78=1324
  78. .79=1345
  79. .8=1330
  80. .80=1356
  81. .81=1372
  82. .82=1366
  83. .83=1387
  84. .84=1395
  85. .85=1425
  86. .86=1444
  87. .87=1452
  88. .88=1461
  89. .89=1483
  90. .9=1455
  91. .90=1473
  92. .91=1486
  93. .92=1520
  94. .93=1522
  95. .94=1536
  96. .95=1549
  97. .96=1566
  98. .97=1586
  99. .98=1644
  100. .99=1646
复制代码
***共同提高***

TOP

50# batman


似乎,只1位的数字,耗时都会相对减少,预处理的原因?

TOP

可能以下代码能说明一点问题:
  1. @echo off&setlocal enabledelayedexpansion
  2. for /l %%a in (1,1,1000) do set /a "_%%a=1"
  3. for /l %%a in (1,1,100) do (
  4.     set "t=!time!"
  5.     for /l %%b in (1,1,10000) do set /a _%%a+=1
  6.     set "t1=!time!"&set "a="
  7.     if "!t:~,2!" lss "!t1:~,2!" set "a=+24"
  8.     set /a ".%%a=(!t1:~,2!-!t:~,2!!a!)*360000+(1!t1:~3,2!%%100-1!t:~3,2!%%100)*6000+(1!t1:~6,2!%%100-1!t:~6,2!%%100)*100+(1!t1:~-2!%%100-1!t:~-2!%%100)"
  9. )
  10. set .
  11. pause>nul
复制代码
这是将_1到_100变量计算10000次的时间(ms)用.1到.100变量储存然后列出,本机上运行结果如下:
  1. .1=50
  2. .10=54
  3. .100=69
  4. .11=54
  5. .12=57
  6. .13=57
  7. .14=59
  8. .15=63
  9. .16=62
  10. .17=66
  11. .18=67
  12. .19=70
  13. .2=62
  14. .20=68
  15. .21=70
  16. .22=72
  17. .23=73
  18. .24=75
  19. .25=78
  20. .26=78
  21. .27=80
  22. .28=85
  23. .29=82
  24. .3=78
  25. .30=83
  26. .31=85
  27. .32=87
  28. .33=88
  29. .34=89
  30. .35=90
  31. .36=96
  32. .37=93
  33. .38=97
  34. .39=100
  35. .4=91
  36. .40=97
  37. .41=100
  38. .42=101
  39. .43=103
  40. .44=105
  41. .45=108
  42. .46=109
  43. .47=111
  44. .48=114
  45. .49=116
  46. .5=106
  47. .50=112
  48. .51=114
  49. .52=118
  50. .53=118
  51. .54=119
  52. .55=123
  53. .56=124
  54. .57=126
  55. .58=127
  56. .59=128
  57. .6=119
  58. .60=130
  59. .61=128
  60. .62=133
  61. .63=133
  62. .64=134
  63. .65=137
  64. .66=138
  65. .67=140
  66. .68=141
  67. .69=144
  68. .7=131
  69. .70=143
  70. .71=146
  71. .72=146
  72. .73=147
  73. .74=152
  74. .75=151
  75. .76=154
  76. .77=154
  77. .78=156
  78. .79=159
  79. .8=145
  80. .80=158
  81. .81=160
  82. .82=161
  83. .83=166
  84. .84=175
  85. .85=194
  86. .86=178
  87. .87=174
  88. .88=173
  89. .89=177
  90. .9=159
  91. .90=173
  92. .91=175
  93. .92=176
  94. .93=180
  95. .94=180
  96. .95=182
  97. .96=185
  98. .97=184
  99. .98=191
  100. .99=187
复制代码
从这个运行结果可以看出确实变量名的存储和读取是按照cmd默认序列进行的。
***共同提高***

TOP

本帖最后由 plp626 于 2011-4-23 01:11 编辑
你这样,应该还有很多CALL的耗时在内。
caruko 发表于 2011-4-23 00:24

call的耗时不会计算在内。都是开始时间和结束时间存到变量,然后结束后计算的,再保存到变量内。

TOP

上面那个代码是用set/a定义_?,下面用直接用set,不带参数定义,看看运行结果:
  1. [code]@echo off
  2. for /l %%a in (900 1 999)do call:xp %%a _ 已定义_[1-1000]再定义_?的耗时与直接定义_?变量
  3. echo -------------------
  4. for /l %%a in (900 1 999)do call:xp %%a # 已定义#[1-1000]再定义_?的耗时与直接定义_?变量
  5. pause
  6. :xp
  7. setlocal enabledelayedexpansion
  8.         call:tt
  9.         call:etime t1 t2 one
  10.         for /l %%a in (1,1,1000) do set %2%%a=1
  11.         call:tt
  12.         call:etime t1 t2 two
  13. set/a pp=two/one,r=(two%%one)*10/one
  14. echo 变量: _%1 %3耗时比: !pp!.%r%
  15. endlocal&goto:eof
  16. :tt -------------------------- sub -----------------------------
  17. set t1=%time%
  18. for /l %%a in (1 1 1000)do set _%1=1
  19. set t2=%time%
  20. goto:eof
  21. :etime
  22. setlocal enabledelayedexpansion
  23. set/a rt=1!%2:~-5,2!!%2:~-2!-1!%1:~-5,2!!%1:~-2!,%3+=-6000*("%3>>31")
  24. endlocal&set %3=%rt%&goto:eof
复制代码
[/code]

TOP

你这样,应该还有很多CALL的耗时在内。

TOP

本帖最后由 plp626 于 2011-4-23 00:43 编辑

做了一个变量赋值除了与已有变量数量有关外还和字符串的数据有关,但不是单纯的按ascii码顺序,还没找到规律,大家运行这个代码看看合字符串的顺序

_900到_999这样的变量是按照ascii码顺序的,耗时比值不是单调的。暂对规律不做猜想
  1. @echo off
  2. for /l %%a in (900 1 999)do call:xp %%a _ 已定义_[1-1000]再定义_?的耗时与直接定义_?
  3. 变量
  4. echo -------------------
  5. for /l %%a in (900 1 999)do call:xp %%a # 已定义#[1-1000]再定义_?的耗时与直接定义_?
  6. 变量
  7. pause
  8. :xp
  9. setlocal enabledelayedexpansion
  10.         call:tt
  11.         call:etime t1 t2 one
  12.         for /l %%a in (1,1,1000) do set %2%%a=1
  13.         call:tt
  14.         call:etime t1 t2 two
  15. set/a pp=two/one,r=(two%%one)*10/one
  16. echo 变量: _%1 %3耗时比: !pp!.%r%
  17. endlocal&goto:eof
  18. :tt -------------------------- sub -----------------------------
  19. set t1=%time%
  20. for /l %%a in (1 1 1000)do set/a _%1=1
  21. set t2=%time%
  22. goto:eof
  23. :etime
  24. setlocal enabledelayedexpansion
  25. set/a rt=1!%2:~-5,2!!%2:~-2!-1!%1:~-5,2!!%1:~-2!,%3+=-6000*("%3>>31")
  26. endlocal&set %3=%rt%&goto:eof
复制代码

TOP

返回列表