4

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

  • 检索所有可用文件的列表
  • 选择一个文件进行处理
  • 遍历选定的文件并读取一行/记录进行处理
  • 接收记录,确定解析 from in 并调用其他几个函数,这些函数负责在将模型对象持久化到数据库之前创建模型对象。例如,我创建了不同的功能:用户、会话、浏览器、设备使用、服务器等......

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

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

4

1 回答 1

5

所以我的问题是我是否需要将所有函数转换为协程并安排运行事件循环,或者只是那些会阻塞的函数,

您可能需要转换其中的大多数,但转换应该主要是机械的,归结为更改defasync def,并await在调用其他协程时添加。

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

但是你还需要转换它们的调用者,因为从阻塞函数调用协程是没有用的,除非该函数实现了类似事件循环的功能。另一方面,当从另一个协程调用协程时,一切正常,因为挂起会自动传播到链的顶部。一旦整个调用链由协程组成,顶层的调用链就会使用loop.create_task()or馈送到事件循环中loop.run_until_complete()

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


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

于 2018-04-05T06:37:06.787 回答