# Python asyncpg一个数据库驱动的异步进化之路从“等”这个字说起写Python的时候数据库操作往往是整个程序里最让人头疼的瓶颈。就像你去食堂打饭如果窗口只有一个前面的人还要磨磨蹭蹭挑三拣四你只能干等着。传统同步数据库驱动就是这样——数据库连接少每次查询都得等等完了才能干下一件事。这些年异步编程在Python里越来越火从asyncio到各种异步框架大家都在想办法解决那个“等”字。但有个问题一直被回避数据库驱动这块异步化做得怎么样asyncpg就是在这样的背景下出现的。它专门给PostgreSQL做异步数据库连接完全抛弃了同步模式整个设计都是奔着高性能去的。说它“专为异步而生”一点不过分——整个库的底层都是用Cython写的能直接和libpq交互性能上碾压同类型产品。它能做什么asyncpg最直接的价值让你在异步代码里访问PostgreSQL时不用再忍受阻塞。假如你在写一个FastAPI或aiohttp的后端服务要处理很多并发的数据库请求。如果用传统的psycopg2每个请求进来都得创建一个新连接或者用连接池但连接池在异步环境下表现得相当别扭——你得用ThreadPoolExecutor把它包裹起来否则就会阻塞事件循环。asyncpg直接就是协程式的await conn.fetch()不会阻塞事件循环。这意味着一个进程可以同时处理上千个数据库请求而不需要开很多线程。少了很多上下文切换的开销内存占用也小得多。它还支持高性能的JSON操作、二进制数据的批量插入、预处理语句池等等。特别值得一提的是它的连接池实现——asyncpg.create_pool()非常轻量配合asyncio的事件循环用起来很顺手。怎么上手安装就是一行pip install asyncpg。连接数据库用的是asyncpg.connect()你也可以用asyncpg.create_pool()创建一个连接池。importasyncioimportasyncpgasyncdefmain():connawaitasyncpg.connect(userpostgres,passwordpassword,databasetest,hostlocalhost)# 查询rowsawaitconn.fetch(SELECT * FROM users WHERE id $1,1)# 执行awaitconn.execute(INSERT INTO users (name) VALUES ($1),张三)awaitconn.close()注意看那个$1这是asyncpg的参数占位符和psycopg2的%s不同。用$1、$2这种形式更清晰尤其在参数多的时候。连接池更常用asyncdefmain():poolawaitasyncpg.create_pool(userpostgres,passwordpassword,databasetest,min_size5,max_size20)asyncwithpool.acquire()asconn:rowsawaitconn.fetch(SELECT * FROM users)awaitpool.close()pool.acquire()会从池子里拿一个连接用完了自动归还。连接池有大小限制能防止突发流量把数据库压垮。一些坑和心得第一条别乱改连接参数很多人图方便直接在连接字符串里写死连接池大小、超时之类的参数。但asyncpg的有些参数必须通过connect()的命名参数传递写在连接串里会被忽略。遇到奇怪的连接问题先检查参数传递方式。第二条预处理语句记得重用asyncpg有一个叫“预处理语句缓存”的机制。如果你重复执行相同的SQL比如在一个循环里可以显式使用prepare()来创建预处理语句然后反复执行。这样性能能提升不少因为数据库不用每次重新解析SQL。stmtawaitconn.prepare(INSERT INTO table (a, b) VALUES ($1, $2))foriteminitems:awaitstmt.fetch(item.a,item.b)第三条关注连接泄漏asyncpg的连接池设计得不错但如果你不await某些操作比如忘了在协程里acquire()连接就返回连接就会泄漏。时间长了池子里全是僵尸连接。好在它提供了超时机制acquire()可以设置timeout参数超过多久没拿到连接就抛异常。第四条事务管理asyncpg支持嵌套事务但它的SAVEPOINT机制和你在SQL客户端里手动操作是不一样的。最好显式使用conn.transaction()来管理而不是依赖隐式提交。asyncwithconn.transaction():awaitconn.execute(UPDATE ...)# 如果有异常自动回滚和同类技术的对比说到Python连接PostgreSQL的库主要就几个选择psycopg2老牌同步驱动稳定可靠文档丰富。但它是同步的在异步代码里用需要额外包装。psycopg3psycopg2的升级版原生支持异步性能也不错。但它的API和asyncpg风格不同参数绑定用的是%s。psycopg3正在逐步取代psycopg2但目前生态还没那么成熟。aiopg基于psycopg2的异步包装本质上还是在底层用同步线程做性能不如asyncpg。asyncpg纯异步Cython底层性能是这几家里最强的。它有几个缺点只支持PostgreSQL不支持其他数据库学习曲线比psycopg系列陡一点API差异大部分高级功能比如LISTEN/NOTIFY实现得不够完善。做性能测试的时候asyncpg在连接池、批量插入、大结果集遍历这些场景下通常比psycopg2快3-5倍比aiopg快更多。代价是它更“专”——如果你哪天要换数据库就得重写整个数据层。我倾向的选择如果项目是新写的而且确定只用PostgreSQLasyncpg是毫无疑问的首选。它让异步编程真正贯彻到底不用在异步框架里塞同步数据库代码。如果项目需要兼容多种数据库或者团队对psycopg系列非常熟悉选psycopg3也可以——它也在快速迭代性能差距在缩小。说到底选什么工具还是看场景。但如果你在写高并发的异步服务asyncpg值得你花时间钻研。那种不用再担心数据库操作拖慢事件循环的感觉用过就回不去了。