您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

如何使Tornado中的SQLAlchemy异步?

如何使Tornado中的SQLAlchemy异步?

ORM不适合显式异步编程,也就是说,程序员必须在发生任何使用网络访问的事件时立即生成显式回调。这样做的主要原因是ORM广泛使用了惰性加载模式,该模式或多或少与显式异步不兼容。看起来像这样的代码

user = Session.query(User).first()
print user.addresses

实际上会发出两个单独的查询- 一个当你说first()加载行,接下来当你说user.addresses,在的情况下,该.addresses集合已不存在,或者已经过期。本质上,处理ORM构造的几乎每一行代码都可能在IO上阻塞,因此您会在几秒钟内陷入大量的回调意大利面条,更糟糕的是,这些代码行中的绝大部分实际上 不会在IO上阻塞,因此将回调连接在一起的所有开销(否则将是简单的属性访问操作)也将使程序的效率大大降低。

显式异步模型的主要问题是,它们给复杂系统增加了巨大的Python函数调用开销- 不仅像延迟加载那样在面向用户的方面,而且在系统的内部方面,如何围绕Python数据库API(DBAPI)。为了使sqlAlchemy甚至具有基本的异步支持,将对大多数不使用异步模式的程序,甚至是那些非高度并发的异步程序,施加严重的性能损失。考虑使用sqlAlchemy或任何其他ORM或抽象层,其代码可能如下所示:

def execute(connection, statement):
     cursor = connection.cursor()
     cursor.execute(statement)
     results = cursor.fetchall()
     cursor.close()
     return results

上面的代码执行了看似简单的操作,在连接上执行了一条sql语句。但是,使用像psycopg2的async扩展这样的完全异步的DBAPI,以上代码在IO上至少会阻塞3次。因此,以显式异步方式编写上述代码,即使没有使用异步引擎并且回调实际上并未阻塞,也意味着上述外部函数调用至少变为三个函数调用,而不是一个,不包括所施加的开销由显式异步系统或DBAPI自己调用。因此,一个简单的应用程序将自动获得围绕语句执行的简单抽象的函数调用开销的3倍的损失。在Python中,函数调用开销就是一切

由于这些原因,我仍然对围绕显式异步系统的炒作不感到兴奋,至少在某种程度上,有些人似乎希望所有内容都实现异步,例如交付网页(请参阅node.js)。我建议改用隐式异步系统,尤其是gevent,您可以获得异步模型的所有非阻塞IO好处,而没有结构上的冗长/显式回调的缺点。我将继续尝试理解这两种方法的用例,因此,对于显式异步方法作为解决所有问题的解决方案的吸引力,我感到困惑,例如,如您在使用node.js所看到的那样- 我们正在使用脚本语言减少冗长程度和代码复杂性的第一位,并且对于诸如交付网页之类的简单事情进行显式异步似乎什么也没做,只是添加了样板,如果阻塞IO甚至是一个问题,它也可以通过gevent或类似方法自动化。像这样的情况(许多大容量网站使用同步IO模型就可以了)。基于Gevent的系统已经过生产验证,并且越来越流行,因此,如果您喜欢ORM提供的代码自动功能

:Nick Coghlan指出了他关于显式与隐式异步主题的精彩文章,这也是必须在此处阅读的内容。我还得到了一个更新,那就是pep-3156现在欢迎与gevent的互操作性,从而扭转了其先前对gevent的兴趣,这在很大程度上要归功于Nick的文章。因此,一旦集成了这些方法的系统可用,将来我会推荐使用gevent作为数据库逻辑的混合式To??rnado。

SQLServer 2022/1/1 18:33:00 有545人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶