Hello, everyone, I am programmer C~

I’m sharing a powerful Python signal library with you today: Blinker

1 signal

A signal is a form of notification or communication, and signals are divided into sender and receiver. The sender sends a signal, and the process that receives the signal jumps into the signal handler, then jumps back to its original position to continue execution.

A common Linux signal, Ctrl+C, sends a signal to the system telling it to exit the current process.

The characteristic of a signal is that the sender notifies the subscriber of what is happening. The use of signals is divided into three steps: define signals, monitor signals, send signals.

The communication module in Python that provides the concept of signals is called Blinker.

Blinker is a powerful Python-based signal library that supports both simple point-to-point communication and point-to-multipoint multicast. Flask’s signaling mechanism is based on it. Blinker’s kernel is small but powerful, supporting the following features:

  • Support for registering global naming signals
  • Support for anonymous signals
  • Support custom named signals
  • Support persistent and transient connections with receivers
  • Automatic disconnection from the receiver through weak references
  • Supports sending data of any size
  • Support for collecting return values for signal receivers
  • Thread safety

2 blinker

Installation method:

pip install blinker
Copy the code

2.1 Named Signal

S = signal('king') def animal(args): Print (' I am a small wind, king is back, I am going to visit the mount ') # signal register a receiver.Copy the code

2.2 Anonymous Signal

Blinker also supports anonymous signals without specifying a specific signal value. Each anonymous signal created is independent of each other.

from blinker import Signal s = Signal() def animal(sender): Print (animal) if "__main__" == __name__: s.end () print(animal) if __main__ == __name__: s.end ()Copy the code

2.3 Multicast signal

Multicast signal is a feature which can reflect the advantages of signal. Multiple receivers are registered on the signal, and the sender only needs to send once to transmit the message to multiple receivers.

From blinker import signal s = signal('king') def animal_one(args): print(f' {args}') def animal_two(args): print(args) {args}') s.c onect (animal_one) s.c onect (animal_two) if "__main__" == __name__: s.end (' Your Majesty asked me to tour the mountain and catch a monk to cook dinner! ')Copy the code

2.4 Recipient subscribes to topics

The recipient supports subscribing to the specified topic and only sends a message to the recipient when the specified topic sends a message. This is a good way to distinguish between different topics.

from blinker import signal s = signal('king') def animal(args): Print (f 'I am the small wind, {args} is my eldest brother') s.c onnect (animal, sender = 'elephant') if = = "__main__" __name__ : for I the in [' lions', 'elephant', 'dapeng] : s.send(i)Copy the code

2.5 Decoration method

In addition to functions, there is a simpler way to register signals, that is, decorators.

From blinker import signal s = signal('king') @s.connect def animal_one(args): print(f' {the args} ') @ s.c onnect def animal_two (args) : print (f 'I am a big wind, today's slogan is: {args}') if = = "__main__" __name__ : S. end(' Your Majesty asked me to patrol the mountains and catch a monk for dinner! ')Copy the code

2.6 Decorators for subscriptable topics

One drawback of connect’s registration method with decorators is that it does not subscribe to topics, so there is a more advanced connect_via method that supports subscription topics.

From blinker import signal s = signal('king') @s.connect_via(' elephant ') def animal(args): Print (f 'I am the small wind, {args} is my eldest brother') if = = "__main__" __name__ : for I the in [' lions', 'elephant', 'dapeng] : s.s end (I)Copy the code

2.7 Check whether the signal has a receiver

If it takes a long time for a sender to send a message, to avoid wasting performance without a receiver, you can check whether a signal has a receiver first and send the message only when you are sure that there is a receiver.

from blinker import signal s = signal('king') q = signal('queue') def animal(sender): Print (animal) if "__main__" == __name__: res = s.receivers print(res) if res: S.end () res = q.receivers print(res) if res: q.receivers () else: print(" weakref at 0x10D02AE80; To 'function' at 0x10cedd430 (animal)>Copy the code

2.8 Checking whether the subscriber has subscribed to a signal

You can also check whether the subscriber is sent by a certain signal

from blinker import signals = signal('king')q = signal('queue')def animal(sender): Print (animal)if "__main__" == __name__: res = s.has_receivers_for(animal) print(res) res = q.has_receivers_for(animal) print(res)TrueFalseCopy the code

3. Based on Blinker’s Flask signal

Flask integrates Blinker as a solution for decoupling applications. In Flask, signals are used in scenarios such as before the request arrives and after the request ends. Flask also supports custom signals.

3.1 Simple Flask Demo

from flask import Flask

app = Flask(__name__)

@app.route('/',methods=['GET','POST'],endpoint='index')
def index():
    return 'hello blinker'

if __name__ == '__main__':
    app.run()
Copy the code

When accessing 127.0.0.1:5000, return to the browser Hello Blinker.

3.2 Custom signal

Since Flask integrates signals, they are imported from Flask when used in Flask.

from flask import Flask
from flask.signals import _signals

app = Flask(__name__)

s = _signals.singal('msg')


def QQ(args):
    print('you have msg from QQ')

s.connect(QQ)

@app.route('/',methods=['GET','POST'],endpoint='index')
def index():
    s.send()
    return 'hello blinker'

if __name__ == '__main__':
    app.run()
Copy the code

3.3 Flask has its own signal

In Flask, you can use custom signals as well as native ones. There are many kinds of signals in Flask, as follows:

# request_finished = _message. signal('request-started' _message. signal('request-finished') # execute after request # render before_render_template = _message. signal('before-render-template') Got_request_exception = template_rendered = _message. signal(' template-Rendered ' _signals. Signal ('got-request-exception') # request_tearing_down = _signals. Signal ('request-tearing-down') # Appcontext_tearing_down = _signals. Signal (' AppContext -tearing-down') # Automatically executed after the request context has finished (tearing-down) # Request context APPContext_pushed = _signals. Signal (' AppContext-pushed ') # Request context push when appContext_popped = _signals. Signal (' appContext-popped ') # message_flashed = _signals. Signal ('message-flashed') # Triggered automatically when flask is called to add data to itCopy the code

How is the signal used in Flask before the request arrives

from flask import Flask from flask.signals import _signals, request_started import time app = Flask(__name__) def wechat(args): Print ('you have MSG from wechat') # Request_started. Connect (wechat) @app.route('/',methods=['GET','POST'],endpoint='index') def index(): return 'hello blinker' if __name__ == '__main__': app.run()Copy the code

Flask notifythe receiver when a request comes in via request_started, the wechat function, which executes first before returning the result to the browser.

However, this is not very natural as signals do not support asynchronous methods, so usually in production the receivers of signals are frames configured with asynchronous execution such as the famous asynchronous frame celery in Python.

4 summarizes

Advantages of signal:

  • Decoupled applications: Decompose a coupled application running in serial into multiple levels of execution
  • Publish subscribers: Reduce the use of callers, notifying multiple subscribers at once

Disadvantages of signals:

  • Asynchrony not supported
  • The ability to support subscription topics is limited