统计微秒级程序运行时间

在写代码时需要统计算法时间,看了一些文章后找到了解决办法,这里主要是将参考的两篇文章整合一下,原文链接已经贴在下面了。

参考文献:

1,https://www.cnblogs.com/whiteyun/archive/2009/09/17/1568240.html

2,https://blog.youkuaiyun.com/nowayings/article/details/44812201

主要用到LARGE_INTEGER类型和QueryPerformanceFrequency()函数

LARGE_INTEGER

LARGE_INTEGER是union结构,可用于表示一64位有符号整数值,其结构为:


typedef union _LARGE_INTEGER {
struct {
ULONG LowPart;
LONG HighPart;
} DUMMYSTRUCTNAME;
struct {
ULONG LowPart;
LONG HighPart;
} u;
LONGLONG QuadPart;
} LARGE_INTEGER;

LARGE_INTEGER是一个联合体。设计的非常巧妙。联合体中的3个元素可以被认为是LARGE_INTEGER的3个定义

 

(1)DUMMYSTRUCTNAME由2部分组成。一个是低位的32位整数LowPart。另一个就是高位的整数咯。在小端的情况下。低32位数字在前。高32位在后。

如果将这个64位整数赋值100.可以这么写

LARGE_INTEGER value;
value.LowPart = 100;
value.HighPart = 0;
(2)u由2部分组成。一个是低位的32位整数LowPart。另一个就是高位的整数咯。在大端的情况下。高32位数字在前。低32位在后。
如果将这个64位整数赋值100.可以这么写

LARGE_INTEGER value;
value.u.LowPart = 100;
value.u.HighPart = 0;
(3)当LARGE_INTEGER 等价于LONGLONG的时候。如果将这个64位整数赋值100.可以这么写

LARGE_INTEGER value;
value.QuadPart = 100;

如果你有编译器直接支持64位整数可以直接使用QuadPart(64位),否则分别对LowPart(32位)和HighPart(32位)存取,HighPart的最高位为符号位。 
   
表示数的范围:--3689348814741910324到+4611686018427387903 
   
LARGE_INTEGER的值等4000000000,在内存中的布局: 
   
00   28   6B   EE       00   00   00   00        
(低字节   )       (高字节   )   

 

QueryPerformanceFrequency() - 基本介绍

类型:Win32API

原型:BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);

作用:返回硬件支持的高精度计数器的频率。

返回值:非零,硬件支持高精度计数器;零,硬件不支持,读取失败。
QueryPerformanceFrequency() - 技术特点供WIN9X使用的高精度定时器:QueryPerformanceFrequency()和QueryPerformanceCounter(),要求计算机从硬件上支持高精度定时器。

函数的原形是:
  BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
  BOOL QueryPerformanceCounter (LARGE_INTEGER *lpCount);

数据类型LARGEINTEGER既可以是一个作为8字节长的整数,也可以是作为两个4字节长的整数的联合结构,其具体用法根据编译器是否支持64位而定。该类型的定义如下:
  typeef union _ LARGE_INTEGER
  {
   struct
   {
   DWORD LowPart;
   LONG HighPart;
   };
   LONGLONG QuadPart;
  } LARGE_INTEGER;

在定时前应该先调用QueryPerformanceFrequency()函数获得机器内部计时器的时钟频率。接着在需要严格计时的事件发生前和发生之后分别调用QueryPerformanceCounter(),利用两次获得的计数之差和时钟频率,就可以计算出事件经历的精确时间。测试函数SLEEP(100)的精确持续时间方法:
  LARGE_INTEGER litmp;
  LONGLONG qt1,qt2;
  double dft,dff,dfm;
  QueryPerformanceFrequency(&litmp);//获得时钟频率
  dff=(double)litmp.QuadPart;
  QueryPerformanceCounter(&litmp);//获得初始值
  qt1=litmp.QuadPart;Sleep(100);
  QueryPerformanceCounter(&litmp);//获得终止值
  qt2=litmp.QuadPart;
  dfm=(double)(qt2-qt1);
  dft=dfm/dff;//获得对应的时间值

需要注意的是DFT计算的结果单位是秒。

转载于:https://www.cnblogs.com/llee-123/p/11203283.html

<think>好的,用户现在想了解如何在Python中统计程序运行时间。之前他问过关于写入CSV文件的问题,现在转向性能分析,这可能意味着他在处理数据时需要优化代码执行时间。根据用户提供的引用,尤其是引用[1]和[2],里面有提到使用timeit模块和性能测试的方法,这可能与用户的需求相关。 首先,我需要回顾用户之前的问题和回答。上一次是关于CSV文件写入,现在转向执行时间统计,这可能是一个进阶问题。用户可能已经掌握了基础的文件操作,现在想优化代码性能,所以需要测量时间。 接下来,分析用户提供的引用。引用[1]中的performance.py使用了timeit模块来测量模块的运行时间,并计算平均值、中位数和标准差。这说明用户可能对更详细的性能分析感兴趣,而不仅仅是单次运行时间。引用[2]展示了timeit的基本用法,用Timer来测量代码片段时间。这可能是一个简单的示例,但用户可能需要更多方法。 用户的问题是如何统计程序运行时间,我需要覆盖不同的方法,比如使用time模块、timeit模块、以及更高级的性能分析工具。同时,用户提供的引用提到了并行计算和TVM,这可能意味着用户对性能优化有更深入的需求,但目前的问题集中在时间测量上。 用户可能的需求层次:首先需要基本的时间测量方法,然后可能需要更精确的测量,最后可能涉及性能分析工具。根据引用中的例子,用户可能对代码段多次运行的平均时间感兴趣,而不仅仅是单次运行,所以需要强调timeit的重复和多次运行功能。 另外,用户可能遇到的问题是,如何正确使用这些工具,避免常见错误,比如测量包含不相关代码的时间,或者在测量时间时没有考虑系统时间与CPU时间的区别。需要提醒这些注意事项。 需要考虑用户的使用场景,比如是在开发环境中进行快速测试,还是在生产环境中进行性能监控。不同的场景可能需要不同的工具,比如装饰器适合快速测试,而cProfile适合深入分析。 最后,根据用户提供的引用,尤其是引用[3]和[4],用户可能有并行计算的需求,但在当前问题中,先专注于时间测量,可能后续问题会涉及并行优化。所以回答中需要覆盖基本方法,同时提及更高级的工具,如cProfile和line_profiler,以满足潜在的高级需求。</think>以下是Python中统计程序运行时间的5种常用方法,结合代码示例和性能对比分析: ### 一、基本计时方法 #### 1. `time`模块的`time()`函数 ```python import time start = time.time() # 被测代码 sum(range(10**6)) end = time.time() print(f"执行时间:{end - start:.4f}秒") ``` - 特点:测量真实世界时间(挂钟时间),精度约1ms[^2] #### 2. `time`模块的`perf_counter()`(推荐) ```python start = time.perf_counter() # 被测代码 sum(range(10**6)) end = time.perf_counter() print(f"高精度时间:{end - start:.6f}秒") ``` - 精度:微秒级(1e-6秒),适合短代码测量[^2] ### 二、专业性能分析工具 #### 3. `timeit`模块(最佳实践) ```python import timeit # 单次测量 t = timeit.Timer('sum(range(10**6))') print(f"单次执行时间:{t.timeit(number=100)/100:.6f}秒") # 多次测量取统计值 results = timeit.repeat('sum(range(10**6))', number=100, repeat=5) print(f"平均时间:{np.mean(results)/100:.6f}±{np.std(results)/100:.6f}秒") ``` - 优势:自动多次运行,提供统计结果(与引用[1]的实现原理一致)[^1] #### 4. 上下文管理器(代码复用) ```python class Timer: def __enter__(self): self.start = time.perf_counter() return self def __exit__(self, *args): self.end = time.perf_counter() self.duration = self.end - self.start with Timer() as t: sum(range(10**6)) print(f"上下文时间:{t.duration:.6f}秒") ``` ### 三、高级性能分析 #### 5. `cProfile`模块(调用分析) ```python import cProfile pr = cProfile.Profile() pr.enable() sum(range(10**6)) # 被测代码 pr.disable() pr.print_stats(sort='cumtime') ``` ### 四、方法对比表 | 方法 | 精度 | 适用场景 | 优点 | 缺点 | |--------------------|---------|--------------------------|--------------------------|----------------------| | `time.time()` | 1ms | 粗略计时 | 简单易用 | 精度低,受系统影响大 | | `time.perf_counter`| 0.1μs | 精确单次测量 | 最高精度时钟 | 需手动计算差值 | | `timeit` | 0.1μs | 代码片段性能测试 | 自动统计,消除随机误差 | 需要封装被测代码 | | `cProfile` | 函数级 | 性能瓶颈定位 | 显示完整调用链 | 产生较大性能开销 | | 上下文管理器 | 0.1μs | 代码块计时 | 方便代码集成 | 需自定义实现 | ### 五、性能优化建议 1. 短时测量(<1s)应使用`timeit`重复执行(如引用[1]的`timing_number`参数)[^1] 2. 避免在测量区间内包含无关代码(如I/O操作) 3. 使用`perf_counter`代替`time`获取更高精度[^2] 4. 并行代码测量参考PP模块的特殊处理(如引用[3]的并行计算方案)[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值