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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

TOP

本帖最后由 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

57# hanyeguxing


从你的代码来看,假如CMD预处理时只取一次变量因为是%%而不是!!,而其中变量 a 是排在最后的,所以每次搜索到"a", 也必然搜索到了前面的#数字变量。
那么花的时候必然相同。
或许使用!!试一试会不一样。

TOP

设定
set loop=6000
set "pre1=_"      :: 垃圾变量前缀
set "pre2=_"      :: 待赋值变量前缀
set "med=set "    :: 赋值方式
  1. @echo off&setlocal EnableDelayedExpansion
  2. :: loop值也是垃圾变量的数量,不能过小,便于比较出差异
  3. set/a loop=6000
  4. set/a p=500
  5. set/a num=loop/p
  6. set "pre1=_"      :: 垃圾变量前缀
  7. set "pre2=_"      :: 待赋值变量前缀
  8. set "med=set "    :: 赋值方式
  9. ======================%测试开始%=========================
  10. echo 待测试变量数占垃圾变量数(%loop%个)的比:1/%p%
  11. if "%pre1%"=="%pre2%" (
  12.         echo “垃圾变量名”中【含有】待赋值变量的测试
  13. ) else (
  14.         echo “垃圾变量名”中【不含有】待赋值变量的测试
  15. )
  16. echo ====================================
  17. :: 生成“垃圾变量”
  18. for /l %%a in (1,1,%loop%) do set %pre1%%%a=1
  19. :: 测试赋值耗时变化
  20. for /l %%z in (1 1 %num%)do (set/a tp=tt,tt=0
  21.         set t1=!time!
  22.         for /l %%a in (1 1 %loop%)do %med% %pre2%%%z=1
  23.         set t2=!time!
  24. set/a tt=1!t2:~-5,2!!t2:~-2!-1!t1:~-5,2!!t1:~-2!,tt+="-6000*(tt>>31)"
  25. set /a cc=tt-tp
  26. echo  执行%loop%次%med% %pre2%%%z=1耗时:!tt!,阶差:!cc!
  27. )
  28. pause
复制代码
输出:
  1. 待测试变量数占垃圾变量数(6000个)的比:1/500
  2. “垃圾变量名”中【含有】待赋值变量的测试
  3. =====================================
  4. 执行6000次set _1=1耗时:116,阶差:116
  5. 执行6000次set _2=1耗时:152,阶差:36
  6. 执行6000次set _3=1耗时:185,阶差:33
  7. 执行6000次set _4=1耗时:221,阶差:36
  8. 执行6000次set _5=1耗时:250,阶差:29
  9. 执行6000次set _6=1耗时:286,阶差:36
  10. 执行6000次set _7=1耗时:289,阶差:3
  11. 执行6000次set _8=1耗时:294,阶差:5
  12. 执行6000次set _9=1耗时:299,阶差:5
  13. 执行6000次set _10=1耗时:117,阶差:-182
  14. 执行6000次set _11=1耗时:118,阶差:1
  15. 执行6000次set _12=1耗时:122,阶差:4
复制代码

TOP

设定
set loop=6000
set "pre1=_"      :: 垃圾变量前缀
set "pre2=_"      :: 待赋值变量前缀
set "med=set/a"    :: 赋值方式
  1. @echo off&setlocal EnableDelayedExpansion
  2. :: loop值也是垃圾变量的数量,不能过小,便于比较出差异
  3. set/a loop=6000
  4. set/a p=500
  5. set/a num=loop/p
  6. set "pre1=_"      :: 垃圾变量前缀
  7. set "pre2=_"      :: 待赋值变量前缀
  8. set "med=set "    :: 赋值方式
  9. ======================%测试开始%=========================
  10. echo 待测试变量数占垃圾变量数(%loop%个)的比:1/%p%
  11. if "%pre1%"=="%pre2%" (
  12.         echo “垃圾变量名”中【含有】待赋值变量的测试
  13. ) else (
  14.         echo “垃圾变量名”中【不含有】待赋值变量的测试
  15. )
  16. echo ====================================
  17. :: 生成“垃圾变量”
  18. for /l %%a in (1,1,%loop%) do set %pre1%%%a=1
  19. :: 测试赋值耗时变化
  20. for /l %%z in (1 1 %num%)do (set/a tp=tt,tt=0
  21.         set t1=!time!
  22.         for /l %%a in (1 1 %loop%)do %med% %pre2%%%z=1
  23.         set t2=!time!
  24. set/a tt=1!t2:~-5,2!!t2:~-2!-1!t1:~-5,2!!t1:~-2!,tt+="-6000*(tt>>31)"
  25. set /a cc=tt-tp
  26. echo  执行%loop%次%med% %pre2%%%z=1耗时:!tt!,阶差:!cc!
  27. )
  28. pause
复制代码
输出:
  1. 待测试变量数占垃圾变量数(6000个)的比:1/500
  2. “垃圾变量名”中【含有】待赋值变量的测试
  3. ====================================
  4. 执行6000次set/a _1=1耗时:130,阶差:130
  5. 执行6000次set/a _2=1耗时:223,阶差:93
  6. 执行6000次set/a _3=1耗时:320,阶差:97
  7. 执行6000次set/a _4=1耗时:413,阶差:93
  8. 执行6000次set/a _5=1耗时:516,阶差:103
  9. 执行6000次set/a _6=1耗时:631,阶差:115
  10. 执行6000次set/a _7=1耗时:646,阶差:15
  11. 执行6000次set/a _8=1耗时:637,阶差:-9
  12. 执行6000次set/a _9=1耗时:648,阶差:11
  13. 执行6000次set/a _10=1耗时:124,阶差:-524
  14. 执行6000次set/a _11=1耗时:139,阶差:15
  15. 执行6000次set/a _12=1耗时:147,阶差:8
  16. 请按任意键继续. . .
复制代码

TOP

  1. @echo off&setlocal enabledelayedexpansion
  2. 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
复制代码
电脑太废...看结果
  1. 8:32:28.14开始10000 1 39999
  2. 8:33:11.32赋值完成
  3. 8:34:32.75第一批完成
  4. 8:36:49.43第二批完成
  5. 请按任意键继续. . .
复制代码

TOP

本帖最后由 caruko 于 2011-4-23 08:57 编辑

如果以上成立的话,那么以后写代码,在大量变量存在的空间,能不用!!就尽量不用了。

还有,hanyeguxin 如果你的逐字搜索来说,那么 set _10000 比set _9 快 无法解释。
而且set _x 比所有 _number 慢也无法解释。

逐字搜索,需要类似数据库映射表,这样才会加快速度。但 set _10000 比 set _9 快很多,可见不成立。
而如果搜索一个单字符,也是遍历进行的,那么假如变量字符很长,需要搜索的次数反而应该大大增加吧?

TOP

设定
set loop=10000
set "pre1=_"      :: 垃圾变量前缀
set "pre2=_"      :: 待赋值变量前缀
set "med=set/a"    :: 赋值方式
  1. @echo off&setlocal EnableDelayedExpansion
  2. :: loop值也是垃圾变量的数量,不能过小,便于比较出差异
  3. set/a loop=10000
  4. set/a p=500
  5. set/a num=loop/p
  6. set "pre1=_"      :: 垃圾变量前缀
  7. set "pre2=_"      :: 待赋值变量前缀
  8. set "med=set "    :: 赋值方式
  9. ======================%测试开始%=========================
  10. echo 待测试变量数占垃圾变量数(%loop%个)的比:1/%p%
  11. if "%pre1%"=="%pre2%" (
  12.         echo “垃圾变量名”中【含有】待赋值变量的测试
  13. ) else (
  14.         echo “垃圾变量名”中【不含有】待赋值变量的测试
  15. )
  16. echo ====================================
  17. :: 生成“垃圾变量”
  18. for /l %%a in (1,1,%loop%) do set %pre1%%%a=1
  19. :: 测试赋值耗时变化
  20. for /l %%z in (1 1 %num%)do (set/a tp=tt,tt=0
  21.         set t1=!time!
  22.         for /l %%a in (1 1 %loop%)do %med% %pre2%%%z=1
  23.         set t2=!time!
  24. set/a tt=1!t2:~-5,2!!t2:~-2!-1!t1:~-5,2!!t1:~-2!,tt+="-6000*(tt>>31)"
  25. set /a cc=tt-tp
  26. echo  执行%loop%次%med% %pre2%%%z=1耗时:!tt!,阶差:!cc!
  27. )
  28. pause
复制代码
  1. 待测试变量数占垃圾变量数(10000个)的比:1/500
  2. “垃圾变量名”中【含有】待赋值变量的测试
  3. ====================================
  4. 执行10000次set _1=1耗时:328,阶差:328 // 注释,第一个阶差不做参考
  5. 执行10000次set _2=1耗时:359,阶差:31
  6. 执行10000次set _3=1耗时:432,阶差:73
  7. 执行10000次set _4=1耗时:491,阶差:59
  8. 执行10000次set _5=1耗时:550,阶差:59
  9. 执行10000次set _6=1耗时:603,阶差:53
  10. 执行10000次set _7=1耗时:653,阶差:50
  11. 执行10000次set _8=1耗时:717,阶差:64
  12. 执行10000次set _9=1耗时:775,阶差:58
  13. 执行10000次set _10=1耗时:342,阶差:-433 // 注意垃圾变量数的千分之一
  14. 执行10000次set _11=1耗时:339,阶差:-3
  15. 执行10000次set _12=1耗时:323,阶差:-16
  16. 执行10000次set _13=1耗时:330,阶差:7
  17. 执行10000次set _14=1耗时:348,阶差:18
  18. 执行10000次set _15=1耗时:346,阶差:-2
  19. 执行10000次set _16=1耗时:348,阶差:2
  20. 执行10000次set _17=1耗时:380,阶差:32
  21. 执行10000次set _18=1耗时:384,阶差:4
  22. 执行10000次set _19=1耗时:400,阶差:16
  23. 执行10000次set _20=1耗时:384,阶差:-16
  24. 请按任意键继续. . .
复制代码

TOP

有很多因素影响赋值操作的

TOP

@echo off&setlocal enabledelayedexpansion
set n=10000 1 39999
rem set n=39999 -1 10000
echo %time%开始%n%
for /l %%a in (%n%) do set #%%a=1
echo %time%赋值完成
for /l %%a in (%n%) do set a=!#1 ...
caruko 发表于 2011-4-23 08:37

%和!在for中的耗时明显不一样,一个语块只解释一次%str%,而!str!的解释次数与相应语句的执行次数成正比,假如在六千次循环中分别用%str%和!str!测试,!str!会比%str%多出5999次花在预处理中的耗时

TOP

返回列表