Board logo

标题: [文本处理] 批处理中goto,call和P+JS混编代码的实测效率对比 [打印本页]

作者: aloha20200628    时间: 2022-10-27 21:15     标题: 批处理中goto,call和P+JS混编代码的实测效率对比

本帖最后由 aloha20200628 于 2022-10-27 21:17 编辑

曾以为goto和call都是cmd内部命令,效率级别相当...
曾以为P+JS混编效率应高于纯P...
但实测结果,还真不一定...
借用前几天的帖子(http://www.bathome.net/thread-64179-1-1.html)简化出一个测试题型,即对源文件(1.txt)每行文本逐列插入字符@,再输出到新文件1.new
现通过以下四段代码看一下比对结果

测试样本》顺便找了一个简中编码的文本文件,1000行(行数少不足以彰显差别),文本行掺杂中英文字符,单行字符量≤128
第一段纯P代码》用goto实现循环,实测耗时约 29 秒
第二段纯P代码》不用goto,实测耗时约 5 秒
第三段混编代码》用js逐行处理,实测耗时约 30 秒
第四段混编代码》用js一次性处理全文件,实测耗时约0.05秒(与以上各段比对可忽略不计了)
用整型换算1-3段代码实测结果》6 : 1 : 6

第一段代码
  1. @echo off &setlocal enabledelayedexpansion
  2. echo,%time%
  3. (for /f "delims=" %%F in (1.txt) do (
  4. (call :_insertCharInStr "%%~F" newF)
  5. echo,!newF!
  6. ))>1.new
  7. echo,%time%
  8. endlocal&exit/b
  9. :_insertCharInStr // %1=srcStr %2=newStr //处理1000行文本数据(单行字符量≤128)耗时约29秒
  10. set "srcStr=%~1" &set "sn=" &set "k=0"
  11. :[Loop]
  12. for %%n in (!k!) do (set "cn=!srcStr:~%%n,1!")
  13. if "!cn!"=="" (set "%~2=!sn!" &exit/b)
  14. set "sn=!sn!@!cn!" &set/a "k+=1" &goto:[Loop]
复制代码
第二段代码
  1. @echo off &setlocal enabledelayedexpansion
  2. echo,%time%
  3. (for /f "delims=" %%F in (1.txt) do (
  4. (call :insertCharInStr "%%~F" newF)
  5. echo,!newF!
  6. ))>1.new
  7. echo,%time%
  8. endlocal&exit/b
  9. :insertCharInStr // %1=srcStr %2=newStr //处理1000行文本数据耗时约5秒
  10. set "srcStr=%~1" &(call :strLen srcStr sL) &set "sn=" &set/a "sL-=1"
  11. for /L %%k in (0,1,!sL!) do (set "sn=!sn!@!srcStr:~%%k,1!")
  12. set "%~2=!sn!" &exit/b
  13. :strLen // %1=被测字符串变量名 %2=返回值变量名
  14. (set "str=a!%~1!"
  15. set "len=0"
  16. for /l %%a in (12,-1,0) do (
  17. set/a "len|=1<<%%a"
  18. for %%b in (!len!) do if "!str:~%%b,1!"=="" set/a "len&=~1<<%%a"
  19. )
  20. )
  21. if "%~2" neq "" set/a "%~2=!len!"
  22. exit /b
复制代码
第三段代码
  1. @set @v=1 /*
  2. @echo off &setlocal enabledelayedexpansion
  3. echo,%time%
  4. ::处理1000行数据耗时约30秒
  5. (for /f "delims=" %%F in (1.txt) do (
  6. for /f "delims=" %%v in ('cscript /e:jscript "%~f0" "%%~F" ') do set "newF=%%v"
  7. echo,!newF!
  8. ))>1.new
  9. echo,%time%
  10. endlocal&exit/b
  11. */
  12. var v=WSH.Arguments; //获取命令行参数
  13. WSH.Echo(v(0).replace(/(.)/g,'@$1')); //在字符串中逐列插入字符
复制代码
第四段代码
  1. @set @v=1 /*
  2. @echo off
  3. echo,%time%
  4. ::处理1000行文本数据(单行字符量≤128)耗时约0.05秒
  5. cscript /e:jscript "%~f0" "1.txt"
  6. echo,%time%
  7. exit/b
  8. */
  9. var v=WSH.Arguments; //获取命令行参数
  10. var fso=new ActiveXObject('scripting.filesystemobject');
  11. var alltext=fso.opentextfile(v(0)).readall();
  12. alltext=alltext.replace(/([^\r\n])/g,'@$1'); //在字符串中逐列(排除换行符)插入字符
  13. fso.opentextfile("1.new", 2, true).write(alltext);
复制代码

作者: terse    时间: 2022-10-28 16:41

第一段代码和第二段代码在处理字符串长度上方法不一样,效率也会不一样
第三段代码,假如一千行的文本,相当于启动JS处理一千次,尤其在FOR内部启用JS会影响效率
记得论坛有专门针对CALL GOTO SET FOR等命令的测试
作者: aloha20200628    时间: 2022-10-29 13:19

闲时又用一个6000行的样本练了一把四段代码,代码4仅用了0.08秒,依然是厘秒级秒杀本题,略去不提了。1-3代码的量化耗时比例关系 6:1:6 基本未变,但1和3代码的绝对耗时却飙升到3分钟,令goto版和for(...)外部进程调用版的“钝感”毕现,看来通常用小量样本试过的算法代码,还真经不起大数据样本的折腾。
    细想想,其实从实测结果复读出的还是些常识,无论是驾驭c/c++,还是摆弄“远古而简单”的纯P,都是大道至简,一脉相通,不都是在打磨锤炼“算法及其代码实现”吗 ... 代码量少不一定效率高,样本不足时,利刃和钝器似乎无感。
    记起旧帖中有实例用 for /f ... ('dir ...') 处理几十万项的目录文件,陷入了几小时“不动”的困境,后改用 dir ...>tmp.txt & for /f ... (tmp.txt) 得以解困了事。cmd给每个纯P变量只有8k内存,系统给每个cmd进程只有64M内存,一旦超限了要么系统立即报错退出,要么系统启用磁盘交换文件,脚本的运行效率就会明显降低...
    ok, 这些闲聊仅供那些有心鼓捣纯P代码的人—或是那些有趣在'螺蛳壳里做道场'的玩家们参考吧。




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