asyncio - 有多少协程?
asyncio - how many coroutines?
我已经为 python 应用程序苦苦挣扎了几天,我希望在该应用程序中查找文件夹中的一个或多个文件,并遍历每个文件和其中的每条记录并创建对象保存在 Janusgraph 数据库中。我正在使用的特定 OGM 要求与数据库的事务是在异步使用 asyncio 中完成的。我已经阅读了很多关于 asyncio 的博客和帖子,我想我理解异步、等待、任务等的概念......在我的应用程序中,我定义了几个函数来处理处理的不同部分:
- 检索所有可用文件的列表
- Select 处理一个文件
- 遍历所选文件并读取一个line/record进行处理
- 接收记录,确定从中解析并调用其他几个负责创建模型对象的函数,然后再将它们保存到数据库中。例如,我创建的不同函数:用户、会话、浏览器、DeviceUsed、服务器等...
我理解(我可能是错的)使用 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。
我已经为 python 应用程序苦苦挣扎了几天,我希望在该应用程序中查找文件夹中的一个或多个文件,并遍历每个文件和其中的每条记录并创建对象保存在 Janusgraph 数据库中。我正在使用的特定 OGM 要求与数据库的事务是在异步使用 asyncio 中完成的。我已经阅读了很多关于 asyncio 的博客和帖子,我想我理解异步、等待、任务等的概念......在我的应用程序中,我定义了几个函数来处理处理的不同部分:
- 检索所有可用文件的列表
- Select 处理一个文件
- 遍历所选文件并读取一个line/record进行处理
- 接收记录,确定从中解析并调用其他几个负责创建模型对象的函数,然后再将它们保存到数据库中。例如,我创建的不同函数:用户、会话、浏览器、DeviceUsed、服务器等...
我理解(我可能是错的)使用 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。