async函数多次调用本身不引发冲突,问题源于对共享资源的无序并发访问;应避免复用数据库连接、控制并发数、区分顺序与并发执行、隔离共享状态并使用异步锁。

async 函数多次调用本身不会自动引发冲突,真正导致问题的是对共享资源(如数据库连接、全局变量、文件句柄、API 限流接口)的无序并发访问。关键不在“调用次数”,而在“是否共用状态”和“是否缺乏协调机制”。
避免共享数据库连接实例
多个 async 函数若复用同一个未配置作用域管理的数据库客户端(例如 SqlSugarClient 或 DbContext),极易出现 ConnectionState 不一致、连接被提前关闭或归还池失败等问题。
- 在 Web 应用中,始终将数据库客户端注册为 Scoped 服务,确保每个请求拥有独立实例
- 禁用循环内 new SqlSugarClient() 的写法;批量操作应复用单个 client 实例,并确认
IsAutoCloseConnection = true - 连接字符串中合理设置
Max Pool Size和Connection Timeout,避免连接池耗尽或阻塞等待
控制并发数量,防止资源过载
高频触发多个 async 函数(如批量请求、定时任务触发、事件响应)时,不加限制会压垮下游服务或本地资源。
- 使用 asyncio.Semaphore(Python)、SemaphoreSlim(C#)或轻量锁(如 JS 中基于 Promise 的 mutex)限制同时执行数
- 示例:爬虫场景下设最大并发为 3,则 10 个 URL 会分批执行,而非全部瞬间发出
- 对 HTTP 客户端(如 aiohttp、axios)也建议复用 session/instance,避免重复建连开销
区分顺序执行与并发执行的语义
并非所有循环都需要并发。若逻辑依赖前序结果(如链式更新、幂等校验、状态流转),强行并发反而引入竞态。
- 用
for...of+await实现自然顺序执行,每次迭代等待上一个 async 完成 - 避免
forEach中直接 await —— 它不会暂停循环,实际是并发发起所有调用 - 需并发但又要保序返回时,用
Promise.all或asyncio.gather,它们不改变执行顺序,只聚合结果
隔离共享状态,减少临界区
即使没有线程,异步回调切换也可能造成逻辑交错。修改同一对象、数组或变量时,风险真实存在。
- 优先使用局部变量、不可变数据结构(如 map → new Map、array → [...arr])
- 对必须修改的共享状态,用异步锁(如
asyncio.Lock)包裹写操作 - 避免在多个 async 函数中反复读-改-写同一字段;考虑合并操作或引入原子更新机制(如数据库 UPDATE ... WHERE version = x)











