Signal 默认对 receiver 用弱引用,但实测局部函数、lambda、partial 在函数返回并 gc 之后仍被调用——因为 connect 时的签名缓存 lru_cache(512) 强引用了它们,挤满缓存后才被回收;绑定方法则随对象销毁自动消失;weak=False 会拖住对象。
bulk_create / bulk_update / queryset.update() 都不发 pre_save / post_save;queryset.delete() 在没有 delete 信号时是快速删除(2000 行 3 条 SQL),挂上 post_delete 后要取出对象逐个发信号(23 条 SQL);删 2 万行 0.6 ms → 125.9 ms。
20 个并发请求、每个视图等 0.5 s:uvicorn(ASGI)下 async 与 sync 视图都是约 513 ms;gunicorn 同步 worker(WSGI)下无论 async 还是 sync 都是约 10.1 s。async def 视图要放在 ASGI 服务器上才有并发收益。
用线程名和 get_running_loop() 看视图代码到底跑在哪:ASGI 下 async 视图在主线程的事件循环里,sync 视图在每个请求独立的工作线程里;WSGI 下 sync 视图在 worker 主线程,async 视图在一个临时事件循环里。
sync_to_async 的线程行为:默认 thread_sensitive=True 时同一请求里全部同步代码共用一个线程(10 个 0.2 s 任务 2037 ms);thread_sensitive=False 用线程池(206 ms、10 个线程,50 个任务只用到 14 个线程);不同请求互不影响。
在 async 上下文里直接调用同步 ORM(count、遍历、create、cursor)全部抛 SynchronousOnlyOperation;用 a 前缀方法、async for 或 sync_to_async 才可以;DJANGO_ALLOW_ASYNC_UNSAFE=true 只是关掉检查;真实 uvicorn 服务里表现为 500。
异步 ORM 的限制(Django 6.1.1 / PostgreSQL):外键懒加载与反向关系遍历要用 select_related / async for;async 里没有异步事务;a 前缀方法底层是线程里的同步查询,所以 10 个并发 async 查询排队执行(≈2030 ms、1 个连接)。
同步中间件在 ASGI 下会被适配到线程里:400 次串行请求,没有中间件 0.536 ms → 1 个 sync 中间件 0.681 ms(+0.15 ms),5 个 sync 也只有 0.685 ms;DEBUG 日志会记录 adapted;20 并发下 sync 中间件里 sleep 并不会让请求排队(420 ms vs 413 ms)。
流式响应要让生成器类型与服务器匹配:uvicorn + async 生成器首批 307 ms、5 批分开到达;uvicorn + sync 生成器和 gunicorn + async 生成器都被缓冲到 1526 ms 才一起到,并有警告;客户端断开时 async 生成器的 finally 会执行;uvicorn 单进程 30 个长流 1520 ms,gunicorn 同步 worker 6 个长流 9045 ms。
10 个线程各 +1 共 200 次(期望 2000):get → n += 1 → save() 只剩 347、外面包 atomic 只剩 250;F() 表达式 update、select_for_update、save() 配 F() 都精确得到 2000(414 / 810 / 850 ms)。
事务与异步任务的边界:任务在 atomic 里入队后,提交前还有 50 ms 工作时 worker 40/40 查不到订单;立刻提交或 on_commit 入队时 200/200 查到(窗口很短的情形没有复现竞态);worker 加重试可以补救。
transaction.on_commit 的规则:提交后按注册顺序执行,autocommit 时立即执行;回调抛异常时默认中断后续回调(数据已提交),robust=True 记录日志并继续;savepoint 回滚会丢弃回调;TestCase 里回调不执行,要用 captureOnCommitCallbacks。