Python多任务写库时是否应共享psycopg3 AsyncConnection?
Psycopg3 异步并发写入场景的正确连接使用方式
先直接给三类方案的明确判定:
- 禁止跨并发任务共享同一个
AsyncCursor实例 - 禁止跨并发任务共享同一个
AsyncConnection实例 - 不建议在每个任务中重复编写裸连接初始化代码,生产环境统一使用异步连接池为每个任务分配独立连接。
原因说明
为什么不能共享游标
AsyncCursor本身不是协程安全的,单个游标实例同一时间只能维护一个执行上下文。多个并发任务同时操作同一个游标,会直接打乱SQL执行顺序、混淆不同查询的结果集,轻则拿到错误的返回数据,重则触发数据库协议错误导致连接强制断开。
为什么不能共享连接
PostgreSQL 原生协议在单个连接上不支持多路复用并发查询,不管你在同一个AsyncConnection上创建多少个游标,同一时间连接上只能跑一个请求,Psycopg3内部会自动给后续请求排队,根本达不到并发执行的效果。
更严重的是连接会共享会话状态、事务上下文:A任务刚开启事务还没提交,B任务如果在同一个连接上执行回滚、修改会话参数等操作,会直接破坏A任务的事务逻辑,造成数据写入错误。
为什么不建议每个任务单独建裸连接
你问题里贴的单连接写法本身是单任务串行场景的正确写法,但直接放到每个并发任务里有两个明显问题:
- 数据库连接的创建、销毁开销很高,频繁建连会带来不必要的性能损耗
- 没有连接数管控机制,并发量突增时会瞬间创建大量连接,很容易触发数据库
max_connections上限,导致所有连接请求被拒绝。
你贴的单任务示例代码:
async with await psycopg.AsyncConnection.connect() as aconn: async with aconn.cursor() as cur: await cur.execute(...)
仅适合单任务串行操作、或者一次性极低并发的临时脚本场景,不能直接套用到高并发服务里。
标准实现方案
生产环境直接使用Psycopg3官方提供的AsyncConnectionPool异步连接池,全局只需要初始化一次连接池,每个并发任务执行时从池子里申请独立连接,用完自动归还,既保证并发任务之间的连接完全隔离,又能管控总连接数、复用连接降低开销。
参考实现:
import asyncio import psycopg from psycopg_pool import AsyncConnectionPool async def main(): # 全局初始化一次连接池,根据数据库承载能力配置连接数上下限 async with AsyncConnectionPool( conninfo="dbname=your_db user=your_user password=your_pwd host=127.0.0.1", min_size=5, max_size=20, # 数值不要超过数据库配置的最大连接数限制 ) as pool: # 并发写入任务逻辑 async def batch_write_task(task_seq: int): # 每个任务从池内获取独立连接,退出上下文时自动归还 async with pool.connection() as aconn: async with aconn.cursor() as cur: await cur.execute( "INSERT INTO demo_table (task_mark, create_time) VALUES (%s, now())", (f"task_{task_seq}",) ) # 单连接独立事务,和其他任务完全隔离 await aconn.commit() # 启动100个并发任务执行写入 all_tasks = [asyncio.create_task(batch_write_task(i)) for i in range(100)] await asyncio.gather(*all_tasks) if __name__ == "__main__": asyncio.run(main())
如果是临时跑的一次性脚本、并发量不超过3个,也可以直接在每个任务里新建独立连接跑,不用强制上连接池。
内容的提问来源于stack exchange,提问作者Justin Calareso
相关产品推荐
相关产品推荐

