python asyncpg
2026/5/3 19:17:49 网站建设 项目流程

# 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():conn=awaitasyncpg.connect(user='postgres',password='password',database='test',host='localhost')# 查询rows=awaitconn.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():pool=awaitasyncpg.create_pool(user='postgres',password='password',database='test',min_size=5,max_size=20)asyncwithpool.acquire()asconn:rows=awaitconn.fetch('SELECT * FROM users')awaitpool.close()

pool.acquire()会从池子里拿一个连接,用完了自动归还。连接池有大小限制,能防止突发流量把数据库压垮。

一些坑和心得

第一条:别乱改连接参数

很多人图方便,直接在连接字符串里写死连接池大小、超时之类的参数。但asyncpg的有些参数必须通过connect()的命名参数传递,写在连接串里会被忽略。遇到奇怪的连接问题,先检查参数传递方式。

第二条:预处理语句记得重用

asyncpg有一个叫“预处理语句缓存”的机制。如果你重复执行相同的SQL(比如在一个循环里),可以显式使用prepare()来创建预处理语句,然后反复执行。这样性能能提升不少,因为数据库不用每次重新解析SQL。

stmt=awaitconn.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:老牌同步驱动,稳定可靠,文档丰富。但它是同步的,在异步代码里用需要额外包装。

psycopg3:psycopg2的升级版,原生支持异步,性能也不错。但它的API和asyncpg风格不同,参数绑定用的是%s。psycopg3正在逐步取代psycopg2,但目前生态还没那么成熟。

aiopg:基于psycopg2的异步包装,本质上还是在底层用同步线程做,性能不如asyncpg。

asyncpg:纯异步,Cython底层,性能是这几家里最强的。它有几个缺点:只支持PostgreSQL(不支持其他数据库),学习曲线比psycopg系列陡一点(API差异大),部分高级功能(比如LISTEN/NOTIFY)实现得不够完善。

做性能测试的时候,asyncpg在连接池、批量插入、大结果集遍历这些场景下,通常比psycopg2快3-5倍,比aiopg快更多。代价是它更“专”——如果你哪天要换数据库,就得重写整个数据层。

我倾向的选择

如果项目是新写的,而且确定只用PostgreSQL,asyncpg是毫无疑问的首选。它让异步编程真正贯彻到底,不用在异步框架里塞同步数据库代码。如果项目需要兼容多种数据库,或者团队对psycopg系列非常熟悉,选psycopg3也可以——它也在快速迭代,性能差距在缩小。

说到底,选什么工具还是看场景。但如果你在写高并发的异步服务,asyncpg值得你花时间钻研。那种不用再担心数据库操作拖慢事件循环的感觉,用过就回不去了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询