You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python多任务写库时是否应共享psycopg3 AsyncConnection?

Psycopg3 异步并发写入场景的正确连接使用方式

先直接给三类方案的明确判定:

  • 禁止跨并发任务共享同一个AsyncCursor实例
  • 禁止跨并发任务共享同一个AsyncConnection实例
  • 不建议在每个任务中重复编写裸连接初始化代码,生产环境统一使用异步连接池为每个任务分配独立连接。

原因说明

为什么不能共享游标

AsyncCursor本身不是协程安全的,单个游标实例同一时间只能维护一个执行上下文。多个并发任务同时操作同一个游标,会直接打乱SQL执行顺序、混淆不同查询的结果集,轻则拿到错误的返回数据,重则触发数据库协议错误导致连接强制断开。

为什么不能共享连接

PostgreSQL 原生协议在单个连接上不支持多路复用并发查询,不管你在同一个AsyncConnection上创建多少个游标,同一时间连接上只能跑一个请求,Psycopg3内部会自动给后续请求排队,根本达不到并发执行的效果。
更严重的是连接会共享会话状态、事务上下文:A任务刚开启事务还没提交,B任务如果在同一个连接上执行回滚、修改会话参数等操作,会直接破坏A任务的事务逻辑,造成数据写入错误。

为什么不建议每个任务单独建裸连接

你问题里贴的单连接写法本身是单任务串行场景的正确写法,但直接放到每个并发任务里有两个明显问题:

  1. 数据库连接的创建、销毁开销很高,频繁建连会带来不必要的性能损耗
  2. 没有连接数管控机制,并发量突增时会瞬间创建大量连接,很容易触发数据库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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 05:09:17