1Signal信号是一种通知或通信的方式。信号分为发送方和接收方。发送方发送一个信号,接收方接收到信号的过程会跳转到信号处理函数,执行完再跳回到原来的位置继续执行。Linux中常见的信号,通过键盘输入Ctrl+C,就是给系统发送一个信号,告诉系统退出当前进程。信号的特点是发送者通知订阅者发生了什么。使用一个信号分为3个步骤:定义信号、监听信号、发送信号。Python中提供信号概念的通信模块是blinker。Blinker是一个强大的基于Python的信号库,既支持简单的点对点通信,也支持点对多点的组播。Flask的信号机制就是建立在它之上的。Blinker的内核虽然小,但是功能非常强大。它支持以下特性:支持注册全局命名信号支持匿名信号支持自定义命名信号支持通过弱引用与接收者建立持久和短暂的连接自动断开它们之间的连接支持发送任意大小的数据支持收集信号接收者的返回值Threadsafety2blinker安装方法:pipinstallblinker2.1namedsignalfromblinkerimportsignal#定义一个信号s=signal('king')defanimal(args):print('我是小钻风,王者归来,我是去巡山')#Signalregisterareceivers.connect(animal)if"__main__"==__name__:#Sendsignals.send()2.2Anonymoussignalblinker也支持匿名信号,即不需要指定一个特定的信号值。创建的每个匿名信号都是相互独立的。fromblinkerimportSignals=Signal()defanimal(sender):print('我是小钻风,王者归来,我要去巡山了')s.connect(animal)if"__main__"==__name__:秒。send()2.3多播信号多播信号是一种能体现信号优势的特性。多个接收者注册到信号中,发送者只需发送一次即可将信息传递给多个接收者。fromblinkerimportsignals=signal('king')defanimal_one(args):print(f'Iamalittlediamond,today'ssloganis:{args}')defanimal_two(args):print(f'Iamabig展风,今天的口号是:{args}')s.connect(animal_one)s.connect(animal_two)if"__main__"==__name__:s.send('大王叫我巡山抓僧吃饭!')2.4接收者订阅主题接收者支持订阅指定主题,只有当指定主题发送消息时,才会发送给接收者。这种方法很好地区分了不同的主题。fromblinkerimportsignals=signal('king')defanimal(args):print(f'我是小展风,{args}是我大哥')s.connect(animal,sender='elephant')if"__main__"==__name__:foriin['Lion','Elephant','Doc']:s.send(i)2.5除了函数注册之外,还有一个更简单的信号注册方式,用于装饰器的使用,那就是装饰器。fromblinkerimportsignals=signal('king')@s.connectdefanimal_one(args):print(f'我是小钻石,今天的口号是:{args}')@s.connectdefanimal_two(args):print(f'我是大钻峰,今天的标语是:{args}')if"__main__"==__name__:s.send('大王叫我巡山抓僧吃饭!')2.6可以订阅其中之一主题装饰器connect注册方式的缺点是使用装饰器时无法订阅主题,所以有更高级的connect_via方法支持订阅主题。fromblinkerimportsignals=signal('king')@s.connect_via('elephant')defanimal(args):print(f'我是小战锋,{args}是我大哥')if"__main__"==__name__:foriin['lion','elephant','Dapeng']:s.send(i)2.7检查信号是否有接收者如果发送者在发送消息前需要很长时间准备,为了避免没有接收者造成的性能浪费,可以先检查某个信号是否有接收者,只有在确认有接收者时才发送,这样才准确。fromblinkerimportsignals=signal('king')q=signal('queue')defanimal(sender):print('我是小转风,王回来了,我要去巡山了')s.connect(animal)if"__main__"==__name__:res=s.receiversprint(res)如果res:s.send()res=q.receiversprint(res)ifres:q.send()print("children他们都出去巡山了”){4511880240:}我是小转风,王者归来,我要去巡山{}小朋友们都出去巡山了2.8查看订阅者是否订阅了某个信号.您还可以检查订阅者是否订阅了某个信号。fromblinkerimportsignals=signal('king')q=signal('queue')defanimal(sender):print('我是小转风,王回来了,我要去巡山了')s.connect(animal)if"__main__"==__name__:res=s.has_receivers_for(animal)print(res)res=q.has_receivers_for(animal)print(res)TrueFalse3基于blinker的Flask信号Flask集成blinker作为解耦的解决方案应用程序。在Flask中,信号的使用场景是:请求到达之前,请求结束之后。同时,Flask还支持自定义信号。3.1Flask简单演示fromflaskimportFlaskapp=Flask(__name__)@app.route('/',methods=['GET','POST'],endpoint='index')defindex():return'helloblinker'if__name__=='__main__':当app.run()访问127.0.0.1:5000时,它向浏览器返回helloblinker。3.2自定义信号因为Flask集成了信号,所以在Flask中使用信号的时候需要从Flask中导入。fromflaskimportFlaskfromflask.signalsimport_signalsapp=Flask(__name__)s=_signals.singal('msg')defQQ(args):print('你有来自QQ的消息')s.connect(QQ)@app.route('/',methods=['GET','POST'],endpoint='index')defindex():s.send()return'helloblinker'if__name__=='__main__':app.run()3.3Flask自带的信号除了自定义信号外,还可以使用Flask自带的信号。Flask中有很多种信号,如下:Requestrequest_started=_signals.signal('request-started')#在请求到达之前执行request_finished=_signals.signal('request-finished')#在请求之后执行模板渲染endsbefore_render_template=_signals.signal('before-render-template')#在模板渲染之前执行requesttion')#执行request_tearing_down=_signals.signal('request-tearing-down')#请求执行后自动执行(无论成功与否)appcontext_tearing_down=_signals.signal('appcontext-tearing-down')#自动执行在请求上下文执行完请求上下文后(无论成功与否)appcontext_pushed=_signals.signal('appcontext-pushed')#当请求上下文被推送时执行_signals.signal('appcontext-popped')#请求上下文当pop执行时message_flashed=_signals.signal('message-flashed')#当调用flask向其中添加数据时,会自动触发。以请求到来之前为例,看看如何在Flask中使用信号fromflaskimportFlaskfromflask.signalsimport_signals,request_startedimporttimeapp=Flask(__name__)defwechat(args):print('youhavemsgfromwechat')#从flask中引入预设信号并注册一个函数request_started.connect(wechat)@app.route('/',methods=['GET','POST'],endpoint='index')defindex():return'helloblinker'if__name__=='__main__':app.run()请求来的时候,Flask会去通过request_started通知接收者,也就是微信的函数。此时先执行wechat函数,然后将结果返回给浏览器。不过这种使用方式并不是很地道,因为signal不支持异步方式,所以在生产环境中接收signal一般都是配置异步执行的框架,比如python中大名鼎鼎的异步框架celery。4总结信号的优点:解耦应用:将串行运行的耦合应用分解为多级执行发布订阅者:减少调用者的使用,一次调用通知多个订阅者信号的缺点:不支持异步支持订阅主题以上就是本次分享的全部内容。觉得文章还不错的话,请关注公众号:Python编程学习圈,每日干货分享,发送“J”还能领取大量学习资料。或者去编程学习网了解更多编程技术知识。