首页 > 技术文章 > coroutine - 示例

zzyzz 2017-11-29 19:25 原文

  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 '''

 

推荐阅读