诊断 Python 占用一个 CPU 的问题
早上刚打开 MAC 笔记本 5分钟, 就提示我电池快没电了, 于是感觉给它供电. 紧接着, 就听到风扇呼呼作响, 于是查看 Activity Monitor, 发现有个 Python 进程几乎占用一个CPU, 感觉有 bug, 也许是项目的那个代码没写好. hmm, 生产环境不会也是这样吧?
先确定进程信息
有了进程号, 进程很容易确定.
% ps aux | grep 24315
xiatian 24315 99.3 0.0 36938856 9804 ?? R Mon10PM 1044:13.73 /usr/local/Cellar/python@3.11/3.11.11/Frameworks/Python.framework/Versions/3.11/Resources/Python.app/Contents/MacOS/Python /Users/supra/work/projects/agent-ui/main.py
再做 CPU profiling
py-spy 是一个非常流行的采样 profiler,可以在不修改代码的情况下分析任何正在运行的 Python 程序。
pip install py-spy
py-spy record -o profile.svg --pid 24315
火焰图如下:
前面三行都是 Python 自带 python3.11/threading.py
里面的代码. 最后一行是 concurrent/futures/thread.py)
的代码, 代码如下:
try:
while True:
work_item = work_queue.get(block=True)
if work_item is not None:
work_item.run()
# Delete references to object. See issue16284
del work_item
# attempt to increment idle count
executor = executor_reference()
if executor is not None:
executor._idle_semaphore.release()
del executor
continue
executor = executor_reference()
if _shutdown or executor is None or executor._shutdown:
# Flag the executor as shutting down as early as possible if it
# is not gc-ed yet.
if executor is not None:
executor._shutdown = True
# Notice other workers
work_queue.put(None)
return
del executor
except BaseException:
_base.LOGGER.critical('Exception in worker', exc_info=True)
看上去从 work_queue.get(block=True)
拿 item , 每次拿到的都是 None
. 那么下一个问题就是这个 work_queue 从哪里来的, 为什么会以极快的速度返回一个 None?
交叉验证
要回答上面的问题, 就要深入内存去看这个 work_queue 从哪里来的, 它引用了那些对象, 哪些对象还在引用它. 这样才能确定这个 work_queue 有什么问题. 但是, 在此之前, 我们可以去production 看一下, 看看在prod 的 Linux 上是不是有类似的问题, 结果发现完全没问题, 并且它运行的时间更长.
于是猜测, 这个问题难道只是个 MAC 有关? 或者和 MAC 休眠有关?