1 分享流畅的python一书, coroutine 章节中的出租车仿真的例子. 2 3 from collections import namedtuple 4 import queue 5 import random 6 Event = namedtuple('Event', 'time process action') 7 8 def taxi_simu(ident, trips, start_t =0 ): 9 time = yield Event(start_t, ident, 'get out of garage') 10 for i in range(trips): 11 time = yield Event(time, ident, 'pick up passenger') 12 time = yield Event(time, ident, 'passenger arrive destination') 13 14 yield Event(time, ident, 'off duty, going home') 15 16 17 class Emulator(object): 18 19 def __init__(self, proc_mapping): 20 self.events = queue.PriorityQueue() # 保存排定事件的 PriorityQueue 对象,按时间正向排序。 21 self.process = dict(proc_mapping) # 获取的 procs_map 参数是一个字典(或其他映射),可是又从中构建一个字典,创建本地副本, 22 # 因为在仿真过程中,出租车回家后会从 self.procs 属性中移除,而我们不想修改用户传入的对象 23 ''' 24 优先队列是离散事件仿真系统的基础构件:创建事件的顺序不定,放入这种队列之后,可以按照各个事件排定的时间顺序取出。 25 ''' 26 27 def comupte_duration(self, previous_action): 28 if 'get out of garage' in previous_action: 29 return random.randint(1,3) 30 elif 'pick up passenger' in previous_action: 31 return random.randint(9,100) 32 elif 'passenger arrive destination' in previous_action: 33 return random.randint(5,10) 34 else: 35 return 8 36 def run(self, end_time): 37 for _, process in sorted(self.process.items()): # 使用 sorted 函数获取 self.procs 中按键排序的元素;用不到键,因此赋值给 _。 38 first_event = next(process) # 调用 next(proc) 预激各个协程,向前执行到第一个 yield 表达式,做好接收数据的准备。产出一个 Event 对象。 39 self.events.put(first_event) # 把各个事件添加到 self.events 属性表示的 PriorityQueue 对象中。 40 41 simu_time = 0 # 把 sim_time 变量(仿真钟)归零 42 while simu_time < end_time: 43 if self.events.empty(): # 如果队列中没有未完成的事件,退出主循环 44 print('empty events queue, all events done') 45 break 46 47 current_event = self.events.get() # 获取优先队列中 time 属性最小的 Event 对象;这是当前事件(current_event) 48 simu_time, process_id, previous_action = current_event # 拆包 Event 对象中的数据。这一行代码会更新仿真钟 sim_time,对应于事件发生时的时间。 49 # 这通常是离散事件仿真:每次循环时仿真钟不会以固定的量推进,而是根据各个事件持续的时间推进 50 print('Taxi : ', process_id, process_id * ' ', current_event) # 显示 Event 对象,指明是哪辆出租车,并根据出租车的编号缩进 51 actived_process = self.process[process_id] # 从 self.procs 字典中获取表示当前活动的出租车的协程 52 next_time = simu_time + self.comupte_duration(previous_action) 53 try: 54 next_event = actived_process.send(next_time) # 把计算得到的时间发给出租车协程。协程会产出下一个事件(next_event),或者抛出 StopIteration 异常(完成时) 55 except StopIteration: 56 del self.process[process_id] # 如果抛出了 StopIteration 异常,从 self.procs 字典中删除那个协程 57 else: 58 self.events.put(next_event) # 否则,把 next_event 放入队列中 59 else: 60 msg = '=== end of simulation time : {} events are pending ===' 61 print(msg.format(self.events.qsize())) # 如果循环由于仿真时间到了而退出,显示待完成的事件数量(有时可能碰巧是零, 如 endtime 足够大,就不有 event pending, 都会处理完) 62 63 64 65 66 67 if __name__ == '__main__': 68 taxi_num =5 69 DEPARTURE_INTERVAL = 6 70 end_time = 3333 71 taxis = {i: taxi_simu(i, (i+1)*2, i*DEPARTURE_INTERVAL) 72 for i in range(taxi_num)} 73 74 simu = Emulator(taxis) 75 simu.run(end_time) 76 77 78 ''' 79 OUTPUT, 80 81 Taxi : 0 Event(time=0, process=0, action='get out of garage') 82 Taxi : 0 Event(time=3, process=0, action='pick up passenger') 83 Taxi : 1 Event(time=6, process=1, action='get out of garage') 84 Taxi : 1 Event(time=7, process=1, action='pick up passenger') 85 Taxi : 2 Event(time=12, process=2, action='get out of garage') 86 Taxi : 2 Event(time=15, process=2, action='pick up passenger') 87 Taxi : 3 Event(time=18, process=3, action='get out of garage') 88 Taxi : 3 Event(time=21, process=3, action='pick up passenger') 89 Taxi : 1 Event(time=22, process=1, action='passenger arrive destination') 90 Taxi : 4 Event(time=24, process=4, action='get out of garage') 91 Taxi : 1 Event(time=27, process=1, action='pick up passenger') 92 Taxi : 4 Event(time=27, process=4, action='pick up passenger') 93 Taxi : 3 Event(time=34, process=3, action='passenger arrive destination') 94 Taxi : 3 Event(time=40, process=3, action='pick up passenger') 95 Taxi : 0 Event(time=53, process=0, action='passenger arrive destination') 96 Taxi : 0 Event(time=63, process=0, action='pick up passenger') 97 Taxi : 3 Event(time=86, process=3, action='passenger arrive destination') 98 Taxi : 1 Event(time=94, process=1, action='passenger arrive destination') 99 Taxi : 2 Event(time=94, process=2, action='passenger arrive destination') 100 Taxi : 3 Event(time=96, process=3, action='pick up passenger') 101 Taxi : 2 Event(time=100, process=2, action='pick up passenger') 102 Taxi : 1 Event(time=101, process=1, action='pick up passenger') 103 Taxi : 4 Event(time=108, process=4, action='passenger arrive destination') 104 Taxi : 4 Event(time=116, process=4, action='pick up passenger') 105 Taxi : 3 Event(time=120, process=3, action='passenger arrive destination') 106 Taxi : 3 Event(time=130, process=3, action='pick up passenger') 107 Taxi : 0 Event(time=132, process=0, action='passenger arrive destination') 108 Taxi : 4 Event(time=132, process=4, action='passenger arrive destination') 109 Taxi : 0 Event(time=142, process=0, action='off duty, going home') 110 Taxi : 4 Event(time=142, process=4, action='pick up passenger') 111 Taxi : 3 Event(time=172, process=3, action='passenger arrive destination') 112 Taxi : 3 Event(time=180, process=3, action='pick up passenger') 113 Taxi : 2 Event(time=187, process=2, action='passenger arrive destination') 114 Taxi : 1 Event(time=192, process=1, action='passenger arrive destination') 115 Taxi : 4 Event(time=192, process=4, action='passenger arrive destination') 116 Taxi : 1 Event(time=197, process=1, action='pick up passenger') 117 Taxi : 2 Event(time=197, process=2, action='pick up passenger') 118 Taxi : 4 Event(time=198, process=4, action='pick up passenger') 119 Taxi : 3 Event(time=215, process=3, action='passenger arrive destination') 120 Taxi : 3 Event(time=223, process=3, action='pick up passenger') 121 Taxi : 1 Event(time=231, process=1, action='passenger arrive destination') 122 Taxi : 4 Event(time=236, process=4, action='passenger arrive destination') 123 Taxi : 1 Event(time=238, process=1, action='off duty, going home') 124 Taxi : 4 Event(time=241, process=4, action='pick up passenger') 125 Taxi : 2 Event(time=297, process=2, action='passenger arrive destination') 126 Taxi : 2 Event(time=305, process=2, action='pick up passenger') 127 Taxi : 3 Event(time=322, process=3, action='passenger arrive destination') 128 Taxi : 3 Event(time=329, process=3, action='pick up passenger') 129 Taxi : 4 Event(time=338, process=4, action='passenger arrive destination') 130 Taxi : 4 Event(time=344, process=4, action='pick up passenger') 131 Taxi : 2 Event(time=348, process=2, action='passenger arrive destination') 132 Taxi : 2 Event(time=353, process=2, action='pick up passenger') 133 Taxi : 3 Event(time=357, process=3, action='passenger arrive destination') 134 Taxi : 3 Event(time=366, process=3, action='pick up passenger') 135 Taxi : 4 Event(time=425, process=4, action='passenger arrive destination') 136 Taxi : 4 Event(time=431, process=4, action='pick up passenger') 137 Taxi : 3 Event(time=436, process=3, action='passenger arrive destination') 138 Taxi : 3 Event(time=442, process=3, action='off duty, going home') 139 Taxi : 2 Event(time=446, process=2, action='passenger arrive destination') 140 Taxi : 2 Event(time=452, process=2, action='pick up passenger') 141 Taxi : 4 Event(time=520, process=4, action='passenger arrive destination') 142 Taxi : 2 Event(time=523, process=2, action='passenger arrive destination') 143 Taxi : 4 Event(time=525, process=4, action='pick up passenger') 144 Taxi : 2 Event(time=531, process=2, action='off duty, going home') 145 Taxi : 4 Event(time=622, process=4, action='passenger arrive destination') 146 Taxi : 4 Event(time=632, process=4, action='pick up passenger') 147 Taxi : 4 Event(time=642, process=4, action='passenger arrive destination') 148 Taxi : 4 Event(time=648, process=4, action='pick up passenger') 149 Taxi : 4 Event(time=661, process=4, action='passenger arrive destination') 150 Taxi : 4 Event(time=667, process=4, action='off duty, going home') 151 empty events queue, all events done 152 153 '''