[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]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

评分人数

本帖最后由 caruko 于 2011-4-22 16:28 编辑

并不只是内存的问题。而是CMD的变量存储读取机制问题。

否者,为什么调用第一个变量的速度比调用最后一个变量的速度快几倍?

而且,一定程度上解释了,set 存放变量的时候是排序好的。
并且 set _ 这类代码的作用,说明set 存放变量很可能是 数据库 的方式。

TOP

其实我不是想只说明变量越多,速度越慢的问题,这个经常写bat的一般都有了解。

我希望大家谈谈对“变量的存储、读取” 方面猜测理解。

环境:
先设置1万个变量,从_1到_10000。

测试1:调用“_9999”这个变量1万次,再 调用“_1”这个变量1万次,耗时比 27:6 。

测试2:调用_1,_1000,_10000这3个变量执行1万次计算,3者耗时相差仿佛。调用 _99,_999,_9999,以及唯一的一个字符变量"_x",4者调用耗时也相差仿佛。

测试3:将_1--_10000这一万个变量都调用一次 ≈ 调用 _5 | _5000 这些变量一万次。


从上面测试结果来看:
1.  "变量增多,耗时越多"的原因,跟内存的关系不大!!因为1万个小变量不会导致内存不够,其它程序语言变量没有多到阀值,多少也不会有明显影响。

2.  变慢的原因可能跟批处理在预处理变量时,进行变量名查找匹配的速度有关。

3.  批处理内应该有一张表,按照排序好的顺序,存储着变量名(也可能含有以字符类型存储的变量值,或者内存指针)。

4.  批处理在预处理变量时,遍历变量表,取出匹配的变量名,再取得该变量的值。

5.  批处理在读取变量表时,很可能有一个复制(或者别的)操作(这可能是变量越多越慢的另一个原因)。 因为从一万个元素的Array(10000)数组中读取Array[0] 的速度,绝对不会比从Array(1)中读取Array[0]的速度慢太多。而这在批处理中的差距是几千倍。

大家有什么看法??

TOP

C的变量,内存的读取,我有一定了解。但是C是编译程序,静态变量一般直接翻译成地址。

如果调用一万个变量 比 调用一万个变量中的 一个变量 速度慢,或许可以解释成CPU缓存与寻址之类的说法。


但是,从 读取 _1 跟 _9999 的速度不一样,以及_9,_5000等调用测试,可以看出:
批处理遍历了一个表,排在前列的读取速度快,排在后面的读取速度慢,而且从表开始到结束,读取耗时是匀速增加的。表的内容是经过排序的,与"set _"的输出一致。

这个结论很容易验证,我已给出代码,大家都可以自己试试,调用不同位置的变量,看看速度有那些差距。


验证过上面的代码后:
如果真的有“变量表”存在,那么P跟C的变量存储方式肯定不同。
set x=1 速度快于 set /a x=1 ,则很可能说明:变量是以字符类型存储的。如果是指针,那么速度应该差不多。

TOP

本帖最后由 caruko 于 2011-4-22 19:00 编辑

12# plp626

for /l %%i in (1,1,10000)  set /a _10000+=2

for /l %%i in (1,1,10000)  set /a _9999+=2

预处理会有很大差距吗?
_9 , _99 , _9999  耗时几乎相同
_1,_100,_10000 耗时也几乎相同

但是 _9 >> _10000,可否说明,跟预处理无关?

1万次 _9 耗时 23.1 秒
1万次 _10000 耗时 5.3 秒

每次的执行时间虽然不固定,但是巨大的差距足以说明问题。

TOP

14# batman

你只执行一次,当然看不出来。 循环一万次试试??
  1. @echo off
  2. for /l %%a in (1,1,10000) do set "_%%a=a"
  3. echo %time%
  4. for /l %%a in (1,1,10000) do set /a _1+=1
  5. echo %time%
  6. for /l %%a in (1,1,10000) do set /a _9999+=1
  7. echo %time%
  8. pause>nul
复制代码

TOP

本帖最后由 caruko 于 2011-4-22 19:27 编辑

17# batman


你13楼代码,没有初始环境!
在最前面加一句
for /l %%a in (1,1,10000) do set /a _%%a=1

附件: 您需要登录才可以下载或查看附件。没有帐号?注册

TOP

18# plp626


你说的这些,就跟《量子力学》与《牛顿定律》一样。
从相对恒定的常规环境中的测试结论,得出的《牛顿定律》仍然可以说明常见现象。
扯那么深远,的确我测试不出来。

TOP

楼上的大哥...
我说了,前提是有一万个变量的测试环境。 然后取第一个_1跟最后一个_9999。

你的代码,相当于环境中总共只有2个变量。
也就是只差一个位置,差距在那里?

请仔细看看我20楼的图,分析一下代码。

TOP

本帖最后由 caruko 于 2011-4-22 20:09 编辑

也就是说,在你的代码中,第2行中添加一句代码。
for /l %%a in (1,1,10000) do set "_%%a=1"

对了,一万就足够了。

TOP

25# plp626


好吧,被你打败了。
你的 CALL执行完,结果为0,没分析你的算法。
但请你直接ECHO %time%吧


20:14:04.89
20:14:26.03
20:14:30.26
请按任意键继续. . .

TOP

29# plp626


你的代码,好像不是 全局 与 局部 的关系啊。
而是2个相对独立的局部。

这样的意义就相当于:
当我们需要大量变量参与计算(计算后这大量的变量需要废弃),而我们只需要计算后的少数几个结果,那么可以setlocal,减少之后其它语句的运行耗时。

TOP

是啊,没考虑过setlocal对此有没有影响。

ZM谈起大量变量影响效率,自己当初也做过生命游戏,做出过耗时3分钟跟15秒的不同版本,但当时没有深想。

现在回想起来,感觉变量大量存在导致的效率问题,超出了其它程序语言的N倍,而且SET 自带排序输出(耗时时很少) 。就猜想set中的变量,很可能是有序存储的。

然后就做了测试,发现了新的问题。
另外就是 _1 跟 _9 之间的效率差距问题,到底是否可能存在有序的变量表?

TOP

36# zm900612

我测试过 set /a _1000+=2 跟 set /a _9999 +=2
排除了字符长度问题,结果仍然。

因为很多人没看懂,所以代码就简单写了2个, _9 耗时比 _10000 长,最能说明问题。

耗时的多少,跟排序后的先后顺序有关。

TOP

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

变量数目越多,操作越慢。 那么基本的设想就是,每次读取一个变量,都对整个“变量组”做了某种操作。

如果假设:这些变量是一个数组,那么以指针的方式读取Array(10000)中的Array[0],与读取Array(1)中的Array[0]并不会有很大的差别,除非在每次取值的时候,都将整个数组复制了一次(或者类似操作才会使得耗时成倍增加)。

还有一种猜想,就是类似数据库的存储方式。这样才会出现在变量大量增加时,耗时成倍增加。同时兼顾排序,输出所有匹配前几个字符的变量(如set _,set _@#等),等功能。


所以,“变量-耗时”的问题估计主要有两个方面。
1:  每次读取一个变量,都操作了整个“变量组”,体现在“总变量多少--耗时”的关系。
2:  读取变量时,会有一个查找操作,查找耗时跟排序位置有关,体现在“变量排序位置--耗时”的关系。

TOP

返回列表