bigywater.tech
Django · 108

自定义 Signal

除了 post_save 这些内置信号,你也可以定义自己的信号,让一个模块「宣布」某件事发生了,而不必知道谁在监听。这篇把自定义信号的定义、发送、sender 匹配、异步 receiver 与容错发送逐项跑一遍。

providing_args
在 Django 6.1.1 里传入会 TypeError,已被移除
sender 相等匹配
类、字符串、实例互不匹配
0.41 s
send() 与 asend() 各调用一个 0.2 s 的 sync 与 async receiver 的总耗时

定义与发送

实测 · 本机执行输出
['email 订单 7 金额 99'] [('send_email', 'ok')]
Signal(providing_args=[...]) → TypeError: Signal.__init__() got an unexpected keyword argument 'providing_args'

sender 怎么匹配

实测 · 本机执行输出
sender=Shop 类: ['for Shop']
sender='shop' 字符串: ["for 'shop'"]
sender=Shop() 实例: []

发送时 sender 传什么,connect 时 sender= 就要传同样的东西。

异步 receiver

实测 · 本机执行输出
send()  同步调用 → 0.41 s,返回 [('slow_sync', 's'), ('slow_async', 'a')]
asend() 协程里调用 → 0.41 s,返回 [('slow_sync', 's'), ('slow_async', 'a')]

我原本以为 asend() 会明显更快,实测两者都是 0.41 s(总和约等于两个 receiver 各自的 0.2 s 相加)——所以本文不能说 asend 让 receiver 并行。同步 receiver 在 asend 里怎么被调度也没有进一步查证。

send_robust

实测 · 本机执行输出
  ok → 'fine' 
  bad → KeyError('missing') (是异常对象)

分步演示

自定义信号
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Python 3.14.7 / Django 6.1.1(默认用 SQLite,其它数据库会在文中注明),用 django.test.Client 或真实的本机服务器进程实测;计时用 time.perf_counter,数字每次运行会有小幅抖动。自建 Signal,不涉及数据库;asend / async receiver 在 Django 5.0 起提供,本文只在 6.1.1 上测
    • 没有验证:在真实视图里发送并结合 on_commit(第 106 篇)、asend 中 sync receiver 的线程调度细节、多线程下的发送、signal 的文档约定(如把 Signal 放在哪个模块)
    京ICP备2026067502号-1京公网安备11010502063487号