Python 进阶
Python 协程实现原理
dict 和 set 实现原理
Python 线程安全
Python 抽象语法树(AST)
Python 日志输出
Python 扩展入门(一)
Python 程序执行原理
Python 垃圾回收
Python 动态创建类
检查工具
PyFrameObject
yield 生成器工作原理
dict 设计与实现
Python 性能分析原理
PyCodeObject
Python 弱引用
Python 性能分析原理(二)
Python 源码分析(一)
Python Annotated
Python 依赖注入
python freelist
python代码编译成pyc
Python mmap 内存映射文件
Python值得学习的内容
async Future 对象
asyncio loop的实现
asyncio.sleep 的实现
asyncio 原理
Python 代码加密
Python Token类型
Python 扩展入门(二)
Python 性能优化
本文档使用 MrDoc 发布
-
+
首页
Python 性能分析原理
### 概述 对于Python的性能分析,一般有以下工具: - `profile` - `cProfile` - `line_profiler` - `memory_profiler` ### 跟踪函数 settrace `sys.settrace` 是 Python 的内置函数,用于在全局范围内设置跟踪函数,这个函数将被解释器在某些事件发生时调用,以便对代码执行进行监视和跟踪。使用 `sys.settrace` 通常用于调试和监视程序的执行,通常有以下使用场景: - 单步执行调试; - 代码覆盖分析; - 运行时检查; - 其他代码分析工具中; 使用 `sys.settrace` 设置的跟踪函数将会在以下几种事件发生时被调用(这些与 `sys.setprofile` 的事件类似): - `call`: 调用函数时; - `line`: 解释器即将执行新一行代码时; - `return`: 一个函数返回时; - `exception`: 发生异常时; - `c_call`: Python 调用 C 扩展函数时(此事件不适用于 settrace); - `c_return`: C 扩展函数返回时(此事件不适用于 settrace); - `c_exception`: C 扩展函数抛出异常时(此事件不适用于 settrace); 跟踪函数的定义与 `sys.setprofile` 类似,同样有三个参数:frame, event, 和 arg。 - `frame` 是当前堆栈帧的引用。 - `event` 是一个字符串,指示事件的类型。 - `arg` 取决于事件类型: 当事件类型为 `line` 或 `call` 时,跟踪函数应返回一个引用自己或另一个跟踪函数的引用。这样处理可以确保后续的行或调用事件能够继续由跟踪函数处理。在 `return` 和 `exception` 事件中通常返回 None。 ### 自己写一个性能分析工具 ``` def trace_calls(frame, event, arg): if event == "call": frame.f_locals['start_time'] = time.time() print(f"{call [{frame.f_code.co_name}] on line:{frame.f_lineno} of {frame.f_code.co_filename}") return trace_calls if event == "line": print(f"line:{frame.f_lineno} in {frame.f_code.co_name}") return trace_calls if event == "return": t = time.time() coast_time = t - frame.f_locals['start_time'] print(f"{return [{frame.f_code.co_name}] totally {coast_time*1000} ms coast") return trace_calls return None # 启动跟踪 sys.settrace(trace_calls) # 需要被性能分析的函数 my_function() # 停止跟踪 sys.settrace(None) ``` ### 多线程的影响 `sys.settrace` 函数用于注册一个全局的`跟踪函数`,该函数会在解释器中执行代码的过程中被调用,主要用于调试目的。 >s 当你在一个线程中设置了跟踪函数,它实际上影响的是整个程序的执行,而非仅仅影响当前线程。 但是 `sys.settrace` 对不同线程的跟踪行为有一些特别之处。主要是,`sys.settrace` 设置的跟踪函数仅会对其被调用时正在运行的线程以及之后创建的线程生效。如果在其他线程已经启动的情况下设置跟踪,那么那些已经在运行的线程不会自动受到跟踪函数的影响。 调用 `sys.settrace(None)` 的目的是停止跟踪。它会影响当前线程的跟踪状态,移除当前线程中设置的跟踪函数。然而,它不会影响其他已经存在的线程,每个线程都需要自己调用该方法来停止跟踪。 ### 线程安全 线程安全除了使用锁,还可以使用`threading.local` 对象 ``` import sys import time import threading from cachetools import LRUCache class MyFile(object): def __init__(self, path): self.path = path self.file = open(self.path, "a+") self.data = LRUCache(maxsize=10000) def register(self): thread_id = threading.current_thread().ident self.data[thread_id] = [] def append(self, content: str): thread_id = threading.current_thread().ident if thread_id not in self.data: return self.data[thread_id].append(content) def commit(self): thread_id = threading.current_thread().ident if thread_id not in self.data: return self.file.writelines(self.data.pop(thread_id)) def clean(self): thread_id = threading.current_thread().ident if thread_id not in self.data: return self.data.pop(thread_id) my_file = MyFile(path="myprofiler.txt") def trace_calls(frame, event, arg): if event == "call": frame.f_locals['start_time'] = time.time() line = f"{int(frame.f_locals['start_time']*1000)} call [{frame.f_code.co_name}] on line:{frame.f_lineno} of {frame.f_code.co_filename}\n" my_file.append(line) return trace_calls if event == "line": my_file.append(f"{int(time.time()*1000)} line:{frame.f_lineno} in {frame.f_code.co_name}\n") return trace_calls if event == "return": t = time.time() coast_time = t - frame.f_locals['start_time'] my_file.append(f"{int(t*1000)} return [{frame.f_code.co_name}] totally {coast_time*1000} ms coast\n") return trace_calls return None class MyProfiler(object): def __enter__(self): self.t1 = time.time() my_file.register() sys.settrace(trace_calls) def __exit__(self, exc_type, exc_val, exc_tb): sys.settrace(None) self.t2 = time.time() coast = (self.t2 - self.t1) * 1000 if coast > 500: my_file.append(f"{int(self.t2*1000)} [MyProfiler] totally {coast} ms coast\n") my_file.commit() else: my_file.clean() with MyProfiler(): other_func() ```
gaojian
2024年10月11日 20:49
分享文档
收藏文档
上一篇
下一篇
微信扫一扫
复制链接
手机扫一扫进行分享
复制链接
关于 MrDoc
觅思文档MrDoc
是
州的先生
开发并开源的在线文档系统,其适合作为个人和小型团队的云笔记、文档和知识库管理工具。
如果觅思文档给你或你的团队带来了帮助,欢迎对作者进行一些打赏捐助,这将有力支持作者持续投入精力更新和维护觅思文档,感谢你的捐助!
>>>捐助鸣谢列表
微信
支付宝
QQ
PayPal
Markdown文件
分享
链接
类型
密码
更新密码