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

[系统相关] 批处理变量表机制的猜测及测试

前面ZM兄谈到变量越多,批执行效率越低的问题。
我做了如下代码测试:

一、
环境中只有1个变量时,速度非常快,一万次调用,耗时不到1秒。

二、
生成一万个变量_1到_10000作为测试环境,测试都执行一万次,现象如下:

1:调用"_1",用时5.5秒。
2:调用"_1000",用时5.5秒。
3:调用"_9999",用时25-27秒。
4:调用"_9",用时25-27秒。
5:调用"_1 To _10000"各一次,总共也是一万次,耗时16秒。
6:调用"_5000"以及"_5","_50",三者用时都在15秒左右。
7:调用字符变量"_x",用时25-27秒。

都是从一万个变量中读取其中一个,"_1"与"_9999"的速度差距巨大!!

直观的可以看20楼的图。

测试结论(猜测)::
批处理遍历了一个变量(名)表,排在前列的读取速度快,排在后面的读取速度慢,而且从表开始到结束,读取耗时是匀速增加的。表的内容是经过排序的,与"set _"的输出一致。

测试代码:
  1. @echo off&setlocal enabledelayedexpansion
  2. for /l %%a in (1,1,10000) do set _%%a=1
  3. echo %time%
  4. for /l %%a in (1 1 10000)do set/a _9+=2
  5. echo %time%
  6. for /l %%a in (1 1 10000)do set/a _10000+=2
  7. echo %time%
  8. pause
复制代码
执行结果
  1. 20:58:43.03
  2. 20:59:04.87
  3. 20:59:09.26
  4. 请按任意键继续. . .
复制代码
2

评分人数

77# zm900612


从当年MS-DOS开始,这里就标记环境变量的段地址值,到windows下都没变过。。。
hanyeguxing 发表于 2011-4-23 09:32


看来还是从DOS过来的厉害啊

不是庐山真面目,只缘身在此山中

TOP

各位都是高手,我都看不懂,你们也写个高效率的系统吧,让我们都开心开心

TOP

本帖最后由 hanyeguxing 于 2011-4-25 11:46 编辑

debug时,只能很容易看到当前环境变量,因为临时的那些位置并不记录在PSP中(所有命令只读写当前环境变量)。。。我们可以换个内存数据工具软件来看嘛
寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

105# hanyeguxing
内存中的地址呢?怎么找不到?
***共同提高***

TOP

本帖最后由 hanyeguxing 于 2011-4-25 11:34 编辑

对于:setlocal-endlocal
每运行一次setlocal将当前位置(本地环境变量位置,也就是命令解释器PSP中2C、2D字节所标记的环境段地址)的环境变量复制到临时位置,并将新变量继续写到当前位置,变量就是这么继承的...
运行endlocal运行时就清除当前位置所有变量,并将对应临时位置的变量复制回来。
这样,无论set还是其他命令(setlocal-endlocal除外),读写的都是本地环境变量位置里的变量
.............................................以上个人观点,哪天有人发现错了,记得不要拍砖。。。
测试:
  1. @echo off
  2. for /l %%a in (0,1,4) do set #%%a=%%a
  3. setlocal enableDelayedExpansion
  4. for /l %%a in (5,1,9) do set #%%a=%%a
  5. set #
  6. pause
  7. endlocal
复制代码


注意,内存分析时,批处理停在 pause 这条命令上,即没有执行 endlocal 呢......
附件: 您需要登录才可以下载或查看附件。没有帐号?注册
寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

关于本次讨论的阶段性结论(个人版):
  
  1、cmd命令解释器在每一次运行时都向内存中重写一次系统变量信息(初始化系统变量),这就说明了为

什么我们无法在cmd中重设系统变量;

  2、cmd命令解释器将每产生的变量按照变量名大写字符的ansi序列机制临时写入内存中,形成一张变量表

并且在变量增加时会重写变量表,而当对已存在的变量进行读写操作时,则是按照ansi序列机制在变量表中进

行搜索比对一直到找到完全匹配的变量,那么当变量表中存在大量变量时,我们读写表前部的变量显然要比表

后部的变量要快,而出于效率上的考虑,我们在编写代码时应该尽量避免出现对大量的变量,同时尽量重复使

用同一变量名,万一要出现大量的变量,应使用setlocal-endlocal开关及时清空这些变量;

  3、对于setlocal-endlocal重写并复原变量的机制暂时没有搞清楚,因为在内存没有找到变量的第二个临时

储存位置。
***共同提高***

TOP

百度搜索下:变量、环境变量、全局变量、局部变量、静态变量、变量名污染、堆栈……
内容虽然不是很多,可能与批处理也无关,不过一些观点还是值得参考的!~
寂寞是黑白的,但黑白不是寂寞,是永恒。BAT 需要的不是可能,而是智慧。

TOP

那清空了本地化操作之后呢?命令解释器是再次复制系统变量进入本地吗?
还有setlocal呢?前后都是本地化操作,为什么endlocal之后能还原上一个setlocal之后的操作呢?

TOP

本帖最后由 hanyeguxing 于 2011-4-24 06:18 编辑

运行批处理时,命令解释器就复制了系统环境变量进入本地,这些系统变量也就本地化了,而 set 的都是本地,所以用set 也只改变本地环境变量
打个比方,系统变量为其他位置的一个源文件,系统变量本地化就像为他在当前目录创建快捷方式,快捷方式可以随意访问源文件。
而 set 这些本地化的系统变量就相当于修改了快捷方式名称,如何修改都不会改变源文件的名称
寒夜孤星:在没有说明的情况下,本人所有代码均运行在 XP SP3 下 (有问题请发贴,QQ临时会话已关闭)

TOP

本帖最后由 zm900612 于 2011-4-23 15:05 编辑

99# plp626


我理解错了...而且初中高中的数学,我都没怎么听课,喜欢用自己的方法东拼西凑解题

98# batman


噢,怪不得,我还纳闷老兄怎么可能把这忘了


这话题越来越好玩了,斑竹们继续吵架,我是跑龙套的群众演员,等结果

TOP

95# zm900612
我说的就是这个意思,只是没有说明罢了,呵呵。。。
***共同提高***

TOP

从大量的测试推断cmd.exe在每次运行时就会用以下命令向内存写入信息从而来设置环境变量:
  1. set "ALLUSERSPROFILE=C:\Documents and Settings\All Users"
  2. set "APPDATA=C:\Documents and Settings\Administrator\Application Data"
  3. set "CommonProgramFiles=C:\Program Files\Common Files"
  4. set "COMPUTERNAME=PC-200901071258"
  5. set "ComSpec=C:\WINDOWS\system32\cmd.exe"
  6. set "FP_NO_HOST_CHECK=NO"
  7. set "HOMEDRIVE=C:"
  8. set "HOMEPATH=\Documents and Settings\Administrator"
  9. set "LOGONSERVER=\\PC-200901071258"
  10. set "NUMBER_OF_PROCESSORS=2"
  11. set "OS=Windows_NT"
  12. set "Path=C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Program Files\Common Files\Thunder Network\KanKan\Codecs;C:\Program Files\StormII\Codec;C:\Program Files\StormII"
  13. set "PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH"
  14. set "PROCESSOR_ARCHITECTURE=x86"
  15. set "PROCESSOR_IDENTIFIER=x86 Family 15 Model 107 Stepping 2, AuthenticAMD"
  16. set "PROCESSOR_LEVEL=15"
  17. set "PROCESSOR_REVISION=6b02"
  18. set "ProgramFiles=C:\Program Files"
  19. set "PROMPT=$P$G"
  20. set "SESSIONNAME=Console"
  21. set "SystemDrive=C:"
  22. set "SystemRoot=C:\WINDOWS"
  23. set "TEMP=C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp"
  24. set "TMP=C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp"
  25. set "USERDOMAIN=PC-200901071258"
  26. set "USERNAME=Administrator"
  27. set "USERPROFILE=C:\Documents and Settings\Administrator"
  28. set "windir=C:\WINDOWS"
复制代码
***共同提高***

TOP

还是测试说明问题,但也带来了新问题。。。。
代码:
@echo off&setlocal enabledelayedexpansion
for /l %%a in (1,1,100) do set "d=!d!&echo d"
call :lp _str a
call :lp _str b setlocal endlocal
call : ...
batman 发表于 2011-4-23 13:32


有一点大家想过么?

call的话就有堆栈,有堆栈在内存中是否影响变量的赋值耗时?

昨晚我就用call,当然也和设置的变量数过少有关,得出的结论让我迷路。。。

TOP

“在重新设定path后,debug命令变得无效。”
debug是外部命令,path变量一改变就找不到文件了

TOP

返回列表