每日一博 | Python 异步编程再添一利器
GINO 填补了国内外 asyncio ORM 领域的空白
随着 Tornado 和 asyncio 等框架的陆续涌现,Python 异步编程这个话题也在逐渐升温。在这个烧脑的异步世界里,有没有办法可以既方便快捷、又简单明了地访问数据库呢?GitHub 千星项目 GINO 了解一下!
1. GINO 是谁
GINO 是一个“轻量级”异步 ORM 框架,它的全称是 GINO Is Not ORM,借鉴了 GNU is Not Unix 的递归定义手法。所以,GINO 一定要全!部!大!写!如果像这样“Gino”就变成了人名,你肯定要问一句“这是谁”。
ORM,即关系对象映射(Object-Relational Mapping),是一类开发人员喜闻乐见的效率工具,它们"极大地"提升了写代码的幸福指数。GINO 是用来访问数据库的,也提供了对象映射的工具,那为什么非说 GINO 不是 ORM 呢?
因为物极必反,ORM 在带来生活便利的同时,也是 bug 生长的温床 —— 传统 ORM 往往会选择牺牲明确性(explicitness)来换取便捷性(convenience),再加上 Python 得天独厚的灵活性(flexibility),创造出了一种爆炸式的化学反应。一旦代码初具规模,项目或多或少都会遇到 ORM 反噬的情景:性能莫名其妙的差、出问题找不到原因、为了鸡毛蒜皮的小事大动干戈。随便一句 current_user.name 都有可能触发一大堆意想不到的数据库调用,这代码你让我怎么调试?
传统 ORM 的学习曲线前平后陡,能在快速原型开发中大展身手,但应用到大型项目中却十分考验开发人员的平均水平。
所有这些问题如果再放进异步编程的环境里,那就是 O(n2) 的复杂度了 —— 哦不,是 O(2n)。这对于一款优秀的异步 ORM 框架来说是不可接受的,所以 GINO 是 ORM 但不是一个传统的 ORM,正犹如 GNU 不是一个传统的 Unix 一样,形似而神不似。
所以在 2017 年创作之初,我就给 GINO 定下了两个业绩目标:1) 方便快捷,2) 简单明了。三年后的今天,我索性在 1.0 稳定版发布的前夕做个年终总结。
2. 先说"方便快捷"
"方便快捷"主要说的是开发效率。
重视开发效率的概念对于写 Python 的同学来说可能并不陌生,某些场景下,开发人员的时间确实比机器的时间值钱。所以,传统 ORM 里的对象映射不能丢。
from gino import Gino db = Gino() class User(db.Model): __tablename__ = "users" id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String)
这么定义表结构甚至让人有点小兴奋。咦,为什么这么眼熟?
没有错,这就是 SQLAlchemy ORM 的定义风格。GINO 并不是从头造轮子,而是在 SQLAlchemy core(SQLAlchemy 中负责构建 SQL 的底层核心)的基础上开发的。这么做除了能保持熟悉的味道(以节省学习和迁移成本),更重要的是带来了整个 SQLAlchemy 的生态环境:开箱即用的数据库变更管理工具 Alembic、各种 SQLAlchemy 的增强插件、专业领域的 PostGIS/geoalchemy 等,GINO 全都兼容。
是不是十分方便、十分快捷?不止这样。
GINO 一站式地解决了常用 CRUD 快捷方式、上下文管理(aiocontextvars)、数据库事务封装和嵌套、连接池管理和懒加载等多项便捷功能,无额外依赖关系,即装即用。
daisy = await User.create(name="daisy") await daisy.update(name="Daisy").apply()
GINO 还提供了各大流行异步 Web 框架的定制版插件,能叫上名字的像 Tornado、aiohttp、Sanic、FastAPI/Starlette、Quart 什么的都有,从简单示范到生产环境的各种例子品种齐全,妈妈再也不用担心我不会集成 Web 框架了。
为了让不同应用场景下的用户体验到最大的善意,GINO 目前支持三种不同程度的用法,成功实现了对同期竞品 asyncpgsa 的降维打击:
- 最少侵入型:SQLAlchemy core 原教旨主义者,只有异步执行时才用到 GINO。
- 终身不婚型:天生厌恶"对象",只愿定义"表",空手接 SQL。
- 火力全开型:最大程度的便利,非典型异步 ORM。
最后,虽然是 Python(绝不是黑哈),但 GINO 在执行效率上也没落下。基于 MagicStack 出品必属精品的、一秒可读百万行的 asyncpg,以及 uvloop(可选)的强力加持,GINO 跑起来也是可以飞快的,被广泛应用于诸如实时汇率、聊天机器人、在线游戏等高并发领域,深受俄罗斯和乌克兰人民的爱戴。
3. 再说"简单明了"
Explicit is better than implicit. Simple is better than complex. -- The Zen of Python, PEP 20
Python 之禅完美表达了 GINO 的立场 —— 明确性(explicitness)对于上了规模的异步工程项目来说尤为重要,因此 GINO 的很多设计都受到了明确性的影响。
比如说,GINO 的 Model
是完全无状态的普通 Python 对象(POPO)—— 例如前面的 User
类,它的实例 daisy
就是内存里面的常规对象,你可以用 daisy.name
访问属性,也可以用 daisy.name = "DAISY"
来修改属性,或者用 u = User()
来创建新的实例,这些操作都不会访问数据库,绝对绿色环保无毒副作用。
等到需要操作数据库的时候,你一定会有感知的。比如执行 INSERT
要用 u = await User.create()
,而 UPDATE
则是 await u.update(name="Daisy").apply()
。
其中,
u.update(name="Daisy")
与u.name = "Daisy"
类似,都是只在内存里修改对象的属性,不同的是u.update()
还会返回一个包含本次变更的中间结果,对其执行await xxx.apply()
则会将这些变更应用到数据库里。
这里的 await
就是明确性的关键,意味着我们要跳出去执行数据库操作了。换句话说,没有 await
就没有数据库操作。
另一方面,对于如何将数据库查询结果组装成内存对象及其属性,GINO 也有一套精妙的显式机制 —— 可定制化的加载器 loaders。对于简单直观的一对一加载,GINO 自然是伺候到家的,比如用 u = await User.get(1)
可以直接获取到 ID 为 1 的用户对象。但是对于更复杂的查询,GINO 不会去无端猜测主人的意图,而全权交给用户来明确地定义。加载器的用法也是很简单的,比如一个用户可能写了很多本书:
class Book(db.Model): __tablename__ = "books" id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String) author_id = db.ForeignKey("users.id")
然后这样来加载这种多对一关系,以同时获取所有的书和他们的作者:
query = Book.outerjoin(User).select() loader = Book.load(author=User) async for book in query.gino.load(loader).iterate(): print(book.title, "written by", book.author.name)
很简单的一个外连接查询 Book.outerjoin(User)
,配合一个直观的加载器 Book.load(author=User)
,就实现了:
- 执行 SELECT * FROM books LEFT JOIN users ON ...;
- 将数据库返回结果的每一行中,属于 books 的字段加载成一个 Book 实例;
- 然后将该行中剩下的属于 users 的字段加载成一个 User 实例;
- 最后将 User 实例设置到 Book 实例的 author 属性上。
既简单又明了有没有!你甚至可以手写任何 SQL,然后定制加载器自动加载成期望的对象关系,精准控制加载行为,指哪儿打哪儿。GINO 还有很多类似的特性,在这里就不一一列举了。
4. 优势与不足
随着这几年 GINO 不断演进成熟,Python 开源社区里也相继出现了像 Tortoise ORM、ORM(是的,这个项目就叫 ORM......我真 ORZ。出品方是 Encode,Starlette 就是他们的作品)等优秀的异步 ORM 框架。它们关注的重点与 GINO 稍有不同,但都是同行就不多评价了。
GINO 的最大优势还是在于充分平衡了开发效率和明确性之间的辩证矛盾关系,用 GINO 开发应用程序的时候不用担心会被意料之外的行为所惊吓到,同时也不需要为这种明确性付出过大的工程代价,上手后依然可以快速、快乐地编程。同时,大量的成功案例也证明了 GINO 已经初步具备发布 1.0 稳定版的各种条件,可以谨慎地用于生产环境了。
以下是近来统计到的关于 GINO 的应用案例:
- 笔者工作上开发的一个服务:https://github.com/uc-cdis/metadata-service
- 还是笔者自己写的一个工具:https://github.com/fantix/aintq
- 一个汇率 API 服务:https://exchangeratesapi.io/
- 各种 Telegram、Discord 的 Bot。
- ArchLinux 用户包:https://aur.archlinux.org/packages/python-gino/
- https://github.com/bryanforbes/gino-stubs/
- 俄语教程:https://www.youtube.com/watch?v=WW4rOnfhiQY
- 高性能模板项目:https://github.com/leosussan/fastapi-gino-arq-uvicorn
- 还有几个商用的,但没征得同意就不贴出来了。
另外,GINO 还贴心地提供了中文文档,从上手教程到原理说明应有尽有(虽然文档还在努力编写中!):
GINO 目前的不足之处还有一些,比如没有照顾到 Python 3 的类型提示,因此还不能完全发挥 IDE 的潜能(上面那个 gino-stubs 就是有人受不了了自己写了一个类型注解)。MySQL 目前也是不支持的,但 GINO 从比较早就解耦了不同 SQL 方言和驱动的集成,所以这些功能会陆续在 1.1 和 1.2 版本中跟上。
5. 建设社会主义
GINO 是一个开源项目,所以欢迎大家一起来建设!长期活跃的贡献者还能获赠价值 4888 元 的 PyCharm 专业版全家桶 License 一枚。 目前急需帮助的有:
- 各个 Web 框架插件的维护工作需要多人认领;
- 更多的例子和文档,以及中文、俄文的翻译;
- MySQL 的支持。
以及下面这些一直需要的帮助:
- 用 GINO,找 bug,提建议;
- 修 bug,做功能,提 PR;
- 维护社区,回答问题,参与讨论;
- 最后也是最重要的:去 GitHub 上给 GINO 加一颗星星!
6. 关于作者
I'm a software architect, fan of coding for over 20 years, and now focusing on software engineering, high concurrency and development performance. Python is my chief language, and I worked on Linux for 10 years, managing development teams up to 20 people for 8 years. Big fan of open source, created project GINO with 1000+ GitHub stars.
OPEN SOURCE
Python / 2018-2019 I started to contribute to Python programming language with MagicStack fellows, focusing on the asyncio library.
GINO / 2017-2019 GINO is an ORM library for Python asyncio. It is an integration of SQLAlchemy core and asyncpg.
aioh2 / 2016 This is an integration of an HTTP/2 protocol library and Python 3 asyncio.
tulipcore / 2015 I've implemented the most part of the event loop core of Gevent with pure Python 3 asyncio (tulip) code.
zmq.rs / 2014 It was my attempt to implement the ZeroMQ stack in pure Rust.
ArchLinux / 2013 - 2016 I maintained the packages of a dozen of build toolchains and base libraries of ArchLinux for x32-ABI, e.g. GCC, glibc, openssl, curl, util-linux, etc.
Gevent / 2011 - 2013 I contributed the initial port of Gevent to Python 3, which was later merged into Gevent 1.1 by its new maintainer. I've also ported Greenlet to x32-ABI.
Translations / 2008 - 2015 I was involved/started several translation projects, e.g. Ubuntu, libexif, Twisted, Python-beginners, ZeroMQ, etc.
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Apache Wicket 8.8.0 发布,Java Web 开发框架
Apache Wicket 8.8.0 发布了。Wicket 是一个 Java 语言的 Web 开发框架,与 Struts、WebWork、Tapestry 相类似,其特点在于对 Html 和代码进行了有效的分离(有利于程序员和美工的合作),基于规则的配置(减少了 XML 等配置文件的使用),学习曲线较低(开发方式与 C/S 相似),更加易于调试(错误类型比较少,而且容易定位)。 更新内容如下: Bug [WICKET-6746] - HttpsMapper 无法通过 WebSocket 处理资源 [WICKET-6752] - 一些依赖项包含 CVE [WICKET-6754] - 嵌套容器停止迭代 [WICKET-6755] - MockServletContext 无法解码真实路径 [WICKET-6756] - 当实际需要路径时,避免使用 URL.getFile() [WICKET-6757] - 在进行 mime 类型检测时,避免使用 URL.getFile [WICKET-6758] - 会话超时后,AbstractWebSocketProcessor 中的 NPE 改进 ...
- 下一篇
树莓派基于 Linux 的 Windows XP 现已可用
新的树莓派操作系统Linux Raspbian XP Professional现已可用,该操作系统专门针对Raspberry Pi4设计。 Rasbian XP Professional 是一个仿 XP 外观的 Linux 系统。尽管用户不能在树莓派上拥有完整的 Windows XP 体验,但是该操作系统所提供的用户体验已相当接近Windows XP。 Raspbian XP Professional 附带许多功能,可使人联想到旧的 XP OS。它具有高效的“开始”菜单,顶部带有可用的搜索栏。所有的菜单、图标和任务栏都具有经典的气泡 XP。其甚至包括完整的 LibreOffice 套件来代替Microsoft Office,以满足办公要求。 不过,尽管该操作系统看起来像 Windows XP,但其本质上还是不能原生运行 Windows XP 应用,而是需要借助合适的仿真器。因此,它也确实预装了一些仿真平台 。 如果要运行本机 Windows 应用程序,可以使用内置的 Windows 98 虚拟机;BOX86则可以运行旧的 PC 游戏。还可以利用其他仿真器,例如 DOSBox、Mupen...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Mario游戏-低调大师作品
- CentOS关闭SELinux安全模块
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Red5直播服务器,属于Java语言的直播服务器
- CentOS8编译安装MySQL8.0.19
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS6,CentOS7官方镜像安装Oracle11G