位置: 编程技术 - 正文

Python实现代码统计工具(终极篇)(python系统代码)

编辑:rootadmin

推荐整理分享Python实现代码统计工具(终极篇)(python系统代码),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:python现成代码,python做代码,代码编程python,代码编程python,python怎么运作代码,代码编程python,代码编程python,python现成代码,内容如对您有帮助,希望把文章链接给更多的朋友!

本文对于先前系列文章中实现的C/Python代码统计工具(CPLineCounter),通过C扩展接口重写核心算法加以优化,并与网上常见的统计工具做对比。实测表明,CPLineCounter在统计精度和性能方面均优于其他同类统计工具。以千万行代码为例评测性能,CPLineCounter在Cpython和Pypy环境下运行时,比国外统计工具cloc1.分别快.5倍和倍,比国内SourceCounter3.4分别快1.8倍和3.6倍。

运行测试环境本文基于Windows系统平台,运行和测试所涉及的代码实例。平台信息如下:

注意,Python不同版本间语法存在差异,故文中某些代码实例需要稍作修改,以便在低版本Python环境中运行。一. 代码实现与优化 为避免碎片化,本节将给出完整的实现代码。注意,本节某些变量或函数定义与先前系列文章中的实现存在细微差异,请注意甄别。 1.1 代码实现首先,定义两个存储统计结果的列表:

其中,rawCountInfo存储粗略的文件总行数信息,列表元素依次为文件行、代码行、注释行和空白行的总数,以及文件数目。detailCountInfo存储详细的统计信息,包括单个文件的行数信息和文件名,以及所有文件的行数总和。

以下将给出具体的实现代码。为避免大段粘贴代码,以函数为片段简要描述。

CalcLinesCh()和CalcLinesPy()函数分别基于C和Python语法判断文件行属性,按代码、注释或空行分别统计。

为提升运行速度,作者将CalcLinesCh()和CalcLinesPy()函数用C语言重写,并编译生成动态链接库。这两个函数的C语言版本实现和使用详见1.2小节。LoadCExtLib()和CalcLines()函数旨在加载该动态链接库并执行相应的C版本统计函数,若加载失败则执行较慢的Python版本统计函数。

上述代码运行于CPython环境,且C动态库通过Python2.5及后续版本内置的ctypes模块加载和执行。该模块作为Python的外部函数库,提供与C语言兼容的数据类型,并允许调用DLL或共享库中的函数。因此,ctypes常被用来在纯Python代码中封装(wrap)外部动态库。

若代码运行于Pypy环境,则需使用cffi接口调用C程序:

cffi用法类似ctypes,但允许直接加载C文件来调用里面的函数(在解释过程中自动编译)。此处为求统一,仍使用加载动态库的方式。

注意"%d files processed..."进度提示。因无法判知输出是否通过命令行重定向至文件(sys.stdout不变,sys.argv不含">out"),该进度提示将换行写入输出文件内。假定代码文件数目为N,输出文件内将含N行进度信息。目前只能利用重定向缺省只影响标准输出的特点,将进度信息由标准错误输出至控制台;同时增加-o选项,以显式地区分标准输出和文件写入,降低使用者重定向的可能性。

此外,调用CalcLines()函数时通过strip()方法剔除文件行首尾的空白字符。因此,CalcLinesCh()和CalcLinesPy()内无需行结束符判断分支。

ReportCounterInfo()输出统计报告。注意,详细报告输出前,会根据指定的排序规则对输出内容排序。此外,空白行术语由EmptyLines改为BlankLines。前者表示该行除行结束符外不含任何其他字符,后者表示该行只包含空白字符(空格、制表符和行结束符等)。

为支持同时统计多个目录和(或)文件,使用ParseTargetList()解析目录-文件混合列表,将其元素分别存入目录和文件列表:

LineCounter()函数基于目录和文件列表进行统计:

然后,添加命令行解析处理:

注意ParseCmdArgs()函数中增加的-s选项。该选项指定输出排序方式,并由r前缀指定升序还是降序。例如,-s 0或-s file表示输出按文件行数升序排列,-s r0或-s rfile表示输出按文件行数降序排列。-c缓存选项最适用于改变输出排序规则时。为支持该选项,使用Json模块持久化统计报告:

注意,json持久化会涉及字符编码问题。例如,当源文件名包含gbk编码的中文字符时,文件名写入detailCountInfo前应通过unicode(os.path.basename(filePath), 'gbk')转换为Unicode,否则dump时会报错。幸好,只有测试用的源码文件才可能包含中文字符。因此,通常不用考虑编码问题。

此时,可调用以上函数统计代码并输出报告:

为测量行数统计工具的运行效率,还可添加如下计时代码:

为避免cProfile开销,此处使用time.clock()测量耗时。 1.2 代码优化 CalcLinesCh()和CalcLinesPy()除len()函数外并未使用其他Python库函数,因此很容易改写为C实现。其C语言版本实现最初如下:

这种实现最接近原来的Python版本,但还能进一步优化,如下:

优化后的版本利用&&运算符短路特性,因此不必考虑越界问题,从而避免动态内存的分配和释放。

Python实现代码统计工具(终极篇)(python系统代码)

作者的Windows系统最初未安装Microsoft VC++工具,因此使用已安装的MinGW开发环境编译dll文件。将上述C代码保存为CalcLines.c,编译命令如下: gcc -shared -o CalcLines.dll CalcLines.c 注意,MinGW中编译dll和编译so的命令相同。-shared选项指明创建共享库,在Windows中为dll文件,在Unix系统中为so文件。

其间,作者还尝试其他C扩展工具,如PyInline。在 setup.py install安装PyInline 执行示例时提示BuildError: error: Unable to find vcvarsall.bat。查阅网络资料,作者下载Microsoft Visual C++ Compiler for Python 2.7并安装。然而,实践后发现PyInline非常难用,于是作罢。

由于对MinGW编译效果存疑,作者最终决定安装VS Express Edition。之所以选择版本,是考虑到CPython2.7的Windows版本基于VS的运行时(runtime)库。安装后,在C:Program FilesMicrosoft Visual Studio 9.0VCbin目录可找到cl.exe(编译器)和link.exe(链接器)。按照网络教程设置环境变量后,即可在Visual Studio Command Prompt命令提示符中编译和链接程序。输入cl /help或cl -help可查看编译器选项说明。

将CalcLines.c编译为动态链接库前,还需要对函数头添加_declspec(dllexport),以指明这是从dll导出的函数: _declspec(dllexport) unsigned int CalcLinesCh(char *line, unsigned char isBlockComment[2]) {..._declspec(dllexport) unsigned int CalcLinesPy(char *line, unsigned char isBlockComment[2]) {... 否则Python程序加载动态库后,会提示找不到相应的C函数。

添加函数导出标记后,执行如下命令编译源代码: cl /Ox /Ot /Wall /LD /FeCalcLines.dll CalcLines.c 其中,/Ox选项表示使用最大优化,/Ot选项表示代码速度优先。/LD表示创建动态链接库,/Fe指明动态库名称。

动态库文件可用UPX压缩。由MinGW编译的dll文件,UPX压缩前后分别为KB和KB;而VS编译过的dll文件,UPX压缩前后分别为KB和KB。经测两者速度相当。考虑到动态库体积,后文仅使用MinGW编译的dll文件。

使用C扩展的动态链接库,代码统计工具在CPython2.7环境下可获得极大的速度提升。相对而言,Pypy因为本身加速效果显著,动态库的性能提升反而不太明显。此外,当待统计文件数目较少时,也可不使用dll文件(此时将启用Python版本的算法);当文件数目较多时,dll文件会显著提高统计速度。详细的评测数据参见第二节。

作者使用的Pypy版本为5.1,可从官网下载Win安装包。该安装包默认包含cffi1.6,后者的使用可参考《Python学习入门手册以及CFFI》或CFFI官方文档。安装Pypy5.1后,在命令提示符窗口输入pypy可查看pypy和cffi版本信息:

若要CPLineCounter在未安装Python环境的主机上运行,应先将CPython版本的代码转换为exe并压缩后,连同压缩后的dll文件一并发布。使用者可将其放入同一个目录,再将该目录加入PATH环境变量,即可在Windows命令提示符窗口中运行CPLineCounter。例如:

二. 精度与性能评测 为检验CPLineCounter统计精度和性能,作者从网上下载几款常见的行数统计工具,即cloc1.(.9MB)、linecount3.7(KB)、SourceCounter3.4(8.MB)和SourceCount_1.0(KB)。

首先测试统计精度。以line.c为目标代码,上述工具的统计输出如下表所示("-"表示该工具未直接提供该统计项):

     经

人工检验,CPLineCounter的统计结果准确无误。linecount和SourceCounter统计也较为可靠。 然后,统计个源代码文件,上述工具的统计输出如下表所示:    

通常,文件总行数和空行数统计规则简单,不易出错。因此,选取这两项统计重合度最高的工具作为基准,即CPLineCounter和linecount。同时,对于代码行数和注释行数,CPLineCounter和SourceCounter的统计结果重合。根据统计重合度,有理由认为CPLineCounter的统计精度最高。

最后,测试统计性能。在作者的Windows XP主机(Pentium G 2.7GHz主频2GB内存)上,统计个C源代码文件,总行数接近千万级。上述工具的性能表现如下表所示。表中仅显示总计项,实际上仍统计单个文件的行数信息。注意,测试时linecount要勾选"目录统计时包含同名文件",cloc要添加--skip-uniqueness和--by-file选项。    

其中,CPLineCounter的性能因运行场景而异,统计耗时少则秒,多则秒。。需要注意的是,cloc仅统计出个文件。以条形图展示上述工具的统计性能,如下所示:

  

图中"Opt-c"表示CPLineCounter以-c选项运行,"CPython2.7+ctypes(O)"表示以CPython2.7环境运行附带旧DLL库的CPLineCounter,"Pypy5.1+cffi1.6(N)"表示以Pypy5.1环境运行附带新DLL库的CPLineCounter,以此类推。

由于CPLineCounter并非纯粹的CPU密集型程序,因此DLL库算法本身的优化并未带来性能的显著提升(对比旧DLL库和新DLL库)。对比之下,Pypy内置JIT(即时编译)解释器,可从整体上极大地&#;&#;&#;升Python脚本的运行速度,加速效果甚至可与C匹敌。此外,性能测试数据会受到目标代码、CPU架构、预热、缓存、后台程序等多方面因素影响,因此不同工具或组合的性能表现可能与作者给出的数据略有出入。

综合而言,CPLineCounter统计速度最快且结果可靠,软件体积也小(exe1.3MB,dllKB)。SourceCounter统计结果比较可靠,速度较快,且内置项目管理信息。cloc文件数目统计误差大,linecount代码行统计误差大,两者速度较慢。但cloc可配置项丰富,并且可自行编译以压缩体积。SourceCount统计速度最慢,结果也不太可靠。

了解Python并行计算的读者也可修改CPLineCounter源码实现,加入多进程处理,压满多核处理器;还可尝试多线程,以改善IO性能。以下截取CountFileLines()函数的部分line_profiler结果:

line_profiler可用pip install line_profiler安装。在待评估函数前添加装饰器@profile后,运行kernprof命令,将给出被装饰函数中每行代码所耗费的时间。-l选项指明逐行分析,-v选项则指明执行后屏显计时信息。Hits(执行次数)或Time(执行时间)值较大的代码行具有较大的优化空间。

由line_profiler结果可见,该函数偏向CPU密集型(~行占用该函数.7%的耗时)。然而考虑到目录遍历等操作,很可能整体程序为IO密集型。因此,选用多进程还是多线程加速还需要测试验证。最简单地,可将~行(即读文件和统计行数)均改为C实现。其他部分要么为IO密集型要么使用Python库,用C语言改写事倍功半。

最后,若仅仅统计代码行数,Linux或Mac系统中可使用如下shell命令: find ./codeDir -name "*.c" -or -name "*.h" | xargs wc -l #除空行外的总行数find ./codeDir -name "*.c" -or -name "*.h" | xargs wc -l #各文件行数及总和

标签: python系统代码

本文链接地址:https://www.jiuchutong.com/biancheng/387038.html 转载请保留说明!

上一篇:在win和Linux系统中python命令行运行的不同(windows中的linux)

下一篇:Python模拟登陆淘宝并统计淘宝消费情况的代码实例分享(python3模拟登录)

  • 什么公司需要缴纳印花税
  • 税金及附加现金流量表
  • 增值税发票认证在哪里
  • 增值税核算应设置什么
  • 发票冲红重开,重开时是按新税率还是旧税率
  • 运输企业内账
  • 可供出售金融资产会计处理
  • 行政事业单位购买固定资产的流程
  • 家庭保洁服务价格表
  • 个人微信转账可以认定劳动关系吗
  • 生育津贴需要连续缴纳社保满一年吗
  • 股权投资需要准备哪些材料
  • 房产租金收入房产税
  • 退休人员工资可以提福利费吗
  • 接受捐赠的固定资产进项税额可以抵扣吗
  • 预收账款转为主营业务收入
  • 公司对公银行账户可以注销吗
  • 税控技术服务费计入什么科目
  • 汽车修理厂可以安装车牌吗
  • 营改增后租金如何交税
  • 停车场企业所得税税率
  • 机打发票多久可以作废
  • 检测费专用增值税的税票税率
  • 收据大写要写整吗
  • 专项维修基金和契税有什么区别
  • 个税累计预缴税额税率表是年还是月
  • 设备销售和安装账务
  • 增值税做账做错怎么处理
  • 公司什么发票可以入账
  • 分公司应收款转总公司会计分录?
  • windows11怎么回到桌面
  • 所得税费用会计编码是什么
  • 总资产报酬率怎么查
  • 收到投资款怎么做记账凭证
  • 招财树的养殖方法
  • 收到违约金赔款计入什么科目
  • 企业预付工程款的会计分录怎么做
  • 代驾服务费如何计算
  • dcc是什么文件
  • 什么情况下计提信用减值损失
  • 旅行社的会计
  • php traits
  • 汉字转拚音
  • 工作服列支什么科目
  • thinkphp框架怎么用
  • db2数据库备份文件为bkd格式
  • 工商罚款计入
  • 劳务分包的形式完成施工任务
  • 财务报表上期金额是指什么意思
  • 预充值发票可以报销吗
  • 残保金申报基数
  • 企业培训费怎么入账
  • 营改增阶段
  • 企业银行存款的流动性强于存货
  • 个体户要怎么注册公司
  • 核定征收也需要报税务报表吗?
  • linux配置mysql数据库远程连接失败的解决方法
  • Win10系统怎么进入控制面板
  • solaris删除文件命令
  • xp系统鼠标右键无法弹出菜单
  • xp系统如何查看系统配置
  • win102020h2版本
  • xp系统提升性能
  • 怎么解圧
  • linux保存配置文件
  • Linux编译内核无法启动
  • linux服务器被尝试登录失败
  • opengl绘制地面
  • js页面点击怎么随机生成图片
  • python笛卡尔积
  • unity公路制作
  • nodejs爬虫技术
  • 绑定安卓
  • JavaScript中的复杂数据类型又称为
  • Python制作钟表代码
  • div-d和div-i
  • jquery detach
  • 小规模纳税人季报网上申报流程
  • 原始凭证审核会计科目吗
  • 国税局巡察整改方案
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设