Signal 是 Django 内置的观察者模式。这篇不涉及模型,只用一个自建的 Signal 把它的规则逐条跑一遍:调用顺序、返回值、sender 过滤、异常、去重与开销。
调用顺序: ['r1', 'r2(x=42)']
send() 返回: [('r1', 'from r1'), ('r2', 'from r2')]
connect 一个没有 **kwargs 的函数 → ValueError: Signal receivers must accept keyword arguments (**kwargs).send() 是同步的:在调用方的线程里一个个执行 receiver,全部执行完才返回。
sender=A: ['only_a', 'any'] sender=B: ['any']
send() 抛出: receiver failed 已执行: ['ok1', 'boom']
send_robust() 已执行: ['ok1', 'boom', 'ok2']
返回: [('ok1', '1'), ('boom', "ValueError('receiver failed')"), ('ok2', '2')]Django 自带的模型信号(post_save 等)用的是 send(),所以某个 receiver 抛异常会打断后面的 receiver,并让调用方(比如 save())也失败。自己发的信号如果不希望被 receiver 拖垮,用 send_robust(),但要自己检查返回值里有没有异常。
同一个函数 connect 两次,send 一次调用 1 次 用了 dispatch_uid: x, x, y → 调用 2 次(x 只算一个) disconnect(dispatch_uid="x") 返回 True 之后调用 1 次 @receiver 装饰器连接后调用: ['f', 'deco']
0 个 receiver:每次 send 0.12 µs 1 个 receiver:每次 send 0.78 µs 5 个 receiver:每次 send 1.87 µs 20 个 receiver:每次 send 5.61 µs
信号机制本身是微秒级的,不需要为它「省」;要注意的是 receiver 里执行的代码。