use*_*723 7 python debugging profiling python-asyncio
我有数千个异步任务正在运行。
某些事情大约需要 10 秒才能完成(某些 CPU 密集型工作)。
这使得程序无法工作,因为某些任务需要在其网络连接上回复消息(比如说 5 秒内)。
我当前的想法是以某种方式拦截事件循环。asyncio 模块中必须有某个区域,在每个 epoll()/select() 之间执行事件循环中的所有当前活动任务。如果我可以在每个任务“恢复”之后插入“elapsed = time.time()”和“elapsed = time.time() - elapsed”,我认为这足以找出占用太多时间的任务时间。
我认为相关代码可能在这里,第79行: https: //github.com/python/cpython/blob/master/Lib/asyncio/events.py
def _run(self):
try:
self._context.run(self._callback, *self._args)
except (SystemExit, KeyboardInterrupt):
raise
except BaseException as exc:
cb = format_helpers._format_callback_source(
self._callback, self._args)
msg = f'Exception in callback {cb}'
context = {
'message': msg,
'exception': exc,
'handle': self,
}
if self._source_traceback:
context['source_traceback'] = self._source_traceback
self._loop.call_exception_handler(context)
self = None # Needed to break cycles when an exception occurs.
Run Code Online (Sandbox Code Playgroud)
但我不知道在这里该怎么做才能打印任何有用的信息;我需要一种方法来确定“self._context.run(...)”将执行代码的哪一行。
在过去的 5 个月里,我不眠不休地试图修复我的代码,但还没有成功。
我尝试过使用 CProfiler、line_profile,但它们都没有帮助。它们告诉我执行一个函数所需的时间以及每行花费的时间。我需要找出的是代码在每次循环迭代之间花费了多少时间。
我尝试过的所有分析/调试工具都不告诉我应该修复什么。在以不同方式重写同一个程序大约 15 次之后,我仍然无法让它工作。
我只是一个非专业程序员,而且仍然是 Python 的新手,但如果我不能解决这个问题,下一步将学习 Rust,这本身将是一个巨大的痛苦,可能在我开始 3 年后,我会让这件事工作起来,预计不会超过两个月。
刚刚编辑文件 /usr/lib/python3.7/asyncio/events.py 并添加:
import time
import signal
import traceback
START_TIME = 0
def handler(signum, frame):
print('##########', time.time() - START_TIME)
traceback.print_stack()
signal.signal(signal.SIGALRM, handler)
Run Code Online (Sandbox Code Playgroud)
第 79 行:
def _run(self):
global START_TIME
try:
signal.alarm(3)
START_TIME = time.time()
self._context.run(self._callback, *self._args)
signal.alarm(0)
except Exception as exc:
cb = format_helpers._format_callback_source(
self._callback, self._args)
msg = f'Exception in callback {cb}'
context = {
'message': msg,
'exception': exc,
'handle': self,
}
if self._source_traceback:
context['source_traceback'] = self._source_traceback
self._loop.call_exception_handler(context)
self = None # Needed to break cycles when an exception occurs.
Run Code Online (Sandbox Code Playgroud)
现在,每当某些异步代码阻塞事件循环 3 秒时,它就会显示一条消息。
发现我的问题是一个简单的“BeautifulSoup(page, 'html.parser')”,其中页面是一个带有大表的 1mb html 文件。