这个例子是由别人写的,但是,对于我理解事件驱动来说至关重要。
我们先来笼统地讲一下,事件驱动究竟是怎样的。
首先,我们以一个生活中的例子。有一家出版社,有几个消费者订阅了这个杂志,当,有新的杂志出来的时候,就会把这个新杂志发送给订阅了的消费者,当消费者拿到杂志开始阅读。
在这个例子中,我们要明确的是,消费者并不是一直轮询等待杂志过来,而是可以做其他的事,当有杂志来的时候,他自己自助的选择看杂志。
而,杂志社和消费者之间也只有订阅的关系。杂志社不会管消费者是男是女,是高是瘦,它所管的仅仅只是订阅的消费者。
所以,事件驱动是一个非常好的降耦合思想。杂志社只管生产杂志,消费者只管看杂志或者其它。
问题是,当杂志社生产出来杂志,是谁,投递到消费者手中。
我们姑且是一个快递小哥,当,杂志社生产出杂志后,就将其发给快递小哥,而快递小哥根据订阅名单,将杂志发给消费者。
这个例子中,其事件是 订阅。
对于程序要想实现上面的逻辑,我们首先需要有一个能够持续不断运行的进程,这个进程是一个引擎般的存在,因为这个引擎要接受各个对象发来的事件,然后找到相应的对象去触发事件。
这个引擎就相当于例子中的快递小哥。
直接上一下程序。
目录结构
代码详解
Event.py 这个文件仅仅只是事件对象,你可以在这个文件中定义各种事件类型。
1 2 3 4 5 class Event (object) : def __init__ (self, type=None) : self.type = type self.dict = {}
Constant.py 这个文件是你的各种事件名字。
1 EVENT_ARTICAL = "Event_Artical"
EventEngine.py 这个是事件引擎,相当于快递小哥的存在,是最核心的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 from multiprocessing import Process, Queueclass EventEngine (object) : def __init__ (self) : self.__eventQueue = Queue() self.__active = False self.__handlers = {} self.__processPool = [] self.__mainProcess = Process(target=self.run) def run (self) : while self.__active: if not self.__eventQueue.empty(): event = self.__eventQueue.get(block=True , timeout=1 ) self.__process(event) else : pass def __process (self, event) : if event.type in self.__handlers: for handler in self.__handlers[event.type]: p = Process(target=handler, args=(event,)) self.__processPool.append(p) p.start() def start (self) : self.__active = True self.__mainProcess.start() def stop (self) : """停止""" self.__active = False for p in self.__processPool: p.join() self.__mainProcess.join() def terminate (self) : self.__active = False for p in self.__processPool: p.terminate() self.__mainProcess.join() def register (self, type, handler) : """注册事件处理函数监听""" try : handlerList = self.__handlers[type] except KeyError: handlerList = [] self.__handlers[type] = handlerList if handler not in handlerList: handlerList.append(handler) def unregister (self, type, handler) : """注销事件处理函数监听""" try : handlerList = self.__handlers[type] if handler in handlerList: handlerList.remove(handler) if not handlerList: del self.__handlers[type] except KeyError: pass def sendEvent (self, event) : self.__eventQueue.put(event)
ListenerTypeOne.py 这个是消费者 1
1 2 3 4 5 6 7 8 9 class ListenerTypeOne : def __init__ (self, username) : self.__username = username def ReadArtical (self, event) : print(u'%s 收到新文章' % self.__username) print(u'%s 正在阅读新文章内容:%s' % (self.__username, event.dict["artical" ]))
ListenerTypeTwo.py 这个是第二种消费者,之所以,有这个消费者是因为这个消费者会 sleep 3 秒,相当于,这个消费者本身就要忙其他的事,然后才来看杂志。
1 2 3 4 5 6 7 8 9 10 import timeclass ListenerTypeTwo : def __init__ (self, username) : self.__username = username def ReadArtical (self, event) : print(u'%s 收到新文章 睡3秒再看' % self.__username) time.sleep(3 ) print(u'%s 正在阅读新文章内容:%s' % (self.__username, event.dict["artical" ]))
PublicAccounts.py 杂志社
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from Event import Eventfrom Constant import ( EVENT_ARTICAL ) class PublicAccounts : def __init__ (self, eventManager) : self.__eventManager = eventManager def writeNewArtical (self) : event = Event(EVENT_ARTICAL) event.dict["artical" ] = u'如何写出更优雅的代码\n' self.__eventManager.sendEvent(event) print(u'公众号发送新文章\n' )
main.py 执行总文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 from ListenerTypeOne import ListenerTypeOnefrom ListenerTypeTwo import ListenerTypeTwofrom EventEngine import EventEnginefrom Constant import ( EVENT_ARTICAL ) from PublicAccounts import PublicAccounts__author__ = 'Jimmy' if __name__ == '__main__' : listner1 = ListenerTypeOne("thinkroom" ) listner2 = ListenerTypeTwo("steve" ) ee = EventEngine() ee.register(EVENT_ARTICAL, listner1.ReadArtical) ee.register(EVENT_ARTICAL, listner2.ReadArtical) for i in range(0 , 20 ): listner3 = ListenerTypeOne("Jimmy" ) ee.register(EVENT_ARTICAL, listner3.ReadArtical) ee.start() publicAcc = PublicAccounts(ee) publicAcc.writeNewArtical()