【发布时间】:2019-05-01 11:27:15
【问题描述】:
https://www.aeracode.org/2018/02/19/python-async-simplified/
如果你调用非阻塞同步函数不会毁了你的一天 函数,像这样:
def get_chat_id(name):
return "chat-%s" % name
async def main():
result = get_chat_id("django")
但是,如果您调用阻塞函数,例如 Django ORM,则 async 函数中的代码看起来相同,但现在是 可能会阻塞整个事件循环的危险代码,因为它不是 等待:
def get_chat_id(name):
return Chat.objects.get(name=name).id
async def main():
result = get_chat_id("django")
您可以看到拥有一个非阻塞函数是多么容易 如果程序员没有超级意识,“意外地”就会阻塞 所有调用它的东西。这就是为什么我建议你永远不要打电话 任何从异步函数同步的东西,但没有安全地执行, 或者事先不知道它是一个非阻塞标准库 函数,如
os.path.join。
所以我正在寻找一种方法来自动捕获此错误的实例。是否有任何用于 Python 的 linter 会将异步函数中的同步函数调用报告为违规?
我可以配置 Pylint 或 Flake8 来执行此操作吗?
我不一定介意它是否也捕捉到上面的第一种情况(这是无害的)。
更新:
正如米哈伊尔的回答所指出的那样,在某种程度上,我意识到这是一个愚蠢的问题。我们需要的是定义 linter 应该检测到的“危险同步函数”。
因此,出于这个问题的目的,我给出以下定义:
“危险的同步函数”是一种执行 IO 操作的函数。例如,这些操作必须由 gevent 进行猴子修补,或者必须包装在 async 函数中,以便事件循环可以进行上下文切换。
(我欢迎对此定义进行任何改进)
【问题讨论】:
-
我们定义了“危险的同步函数”——它是任何
def定义的函数,需要很长时间(>0.05 秒)才能执行。不管是由于 I/O 还是由于其他原因(如繁重的计算)。无论如何,在运行之前都无法检测到这些变体:想象一下eval()随机字符串的代码 - 在真正执行它之前你无法预测会发生什么。 -
不,由于在 cpu 上执行代码而需要很长时间的函数和由于等待 i/o 而需要很长时间的函数之间存在差异。我们在这里只关心后者,因为异步方法对前者毫无帮助
-
异步方法根本无法帮助您使用 Django ORM,除非您完全重写它。我说得通吗?
-
这个问题与 Django ORM 无关。但是由于 Django ORM a) 执行 I/O 并且 b) 不是通过异步调用的,所以这是我希望 linter 捕获的代码示例。换句话说 - 如果我错误地使用了 Django ORM 而不是 asyncpg 我想被警告。
-
老实说,我不认为这是一个愚蠢的问题,如果确实有解决方案,这可能对其他人非常有帮助。我知道这很难确定。
标签: python-3.x python-asyncio pylint flake8