asyncio - 有多少协程?

asyncio - how many coroutines?

我已经为 python 应用程序苦苦挣扎了几天,我希望在该应用程序中查找文件夹中的一个或多个文件,并遍历每个文件和其中的每条记录并创建对象保存在 Janusgraph 数据库中。我正在使用的特定 OGM 要求与数据库的事务是在异步使用 asyncio 中完成的。我已经阅读了很多关于 asyncio 的博客和帖子,我想我理解异步、等待、任务等的概念......在我的应用程序中,我定义了几个函数来处理处理的不同部分:

我理解(我可能是错的)使用 asyncio 的最大优势是针对函数调用通常会因 I/O、数据库事务、网络延迟等而阻塞的情况...

所以我的问题是我是否需要将 所有 我的函数转换为协程并通过事件循环安排到 运行 ,或者只是那些会阻塞的,就像向数据库提交事务一样。我一开始尝试了这种方法,但遇到了各种各样的问题。

So my question is if I need to convert all my functions into coroutines and schedule to run through the event loop, or just the ones that would block,

您可能需要转换它们中的大部分,但转换应该主要是机械的,归结为将 def 更改为 async def,并在调用其他协程时添加 await

显然,您无法避免转换实际阻塞的那些,方法是切换到适当的 asyncio API 或对没有阻塞的那些使用 loop.run_in_executor()。 (DNS解析曾经是后者的一个突出例子。)

但是你还需要转换它们的 调用者 ,因为从阻塞函数调用协程是没有用的,除非函数实现 event-loop-like 功能。另一方面,当从另一个协程调用一个协程时,一切正常,因为挂起会自动传播到链的顶部。一旦整个调用链由协程组成,top-level 将使用 loop.create_task() or loop.run_until_complete().

馈送到事件循环

当然,既不阻塞也不调用阻塞函数的便利函数可以安全地保留 non-async,并且由同步代码或异步代码调用而没有任何区别。


以上适用于 asyncio,它实现了无栈协程。 greenlet 使用了一种不同的方法,其任务封装了调用堆栈,这允许它们在使用普通函数调用的代码中的任意位置切换。不过,Greenlets 比协程更重量级且可移植性更差,所以我会先转换为 asyncio。