03-yield小应用-《流畅的Python》16.9.2出租车协程改编

#出租车队运营仿真
import collections

#优先级列表,用来维护事件列表,用于实现将所有事件按照发生先后顺序执行
class PriorityList:
    def __init__(self):
        self.list=[]

    #获取事件队列中最早发生的事件
    def get_first(self):
        #将事件列表中所有发生事件按照发生事件排序后输出排序后的第一个值
        self.list.sort(key=lambda elem:elem.time)
        return self.list[0]

    #向列表中添加事件
    def add_list(self,event):
        self.list.append(event)

    #从事件队列中删除事件
    def del_list(self,event):
        self.list.remove(event)

    #事件列表是否为空
    def is_empty(self):
        return self.list==[]

#基本单位
#time 事件发生事件  proc 所属出租车协程  action 出租车活动事件
Event=collections.namedtuple('Event','time proc action')

#出租车协程,模拟出租车的各种活动
def taxi_process(ident,trips,start_time=0):
    """
    每次改变状态时创建事件,将控制权让给仿真器
    """
    time=yield Event(start_time,ident,'level garage')
    for i in range(trips):
        time=yield Event(time,ident,'pick up passenger')
        time=yield Event(time,ident,'drop off passenger')

    yield Event(time,ident,'going home')

#测试taxi_process,模拟出租车运行
def main_01():
    taxi=taxi_process(ident=13,trips=2,start_time=0)

    current_state=taxi.send(None) #预激出租车协程
    print(current_state)  #level garge 开出车库

    #第1次接客(发生在离开车库7分钟后),载客行驶事件23分钟
    current_state=taxi.send(current_state.time+7)
    print(current_state) #pick up passenger 接到乘客

    current_state=taxi.send(current_state.time+23)
    print(current_state) #drop off passenger 卸载乘客

    #第2次接客(发生在离开车库5分钟后),载客行驶时间48分钟
    current_state=taxi.send(current_state.time+5)
    print(current_state) #pick up passenger 接到乘客

    current_state=taxi.send(current_state.time+48)
    print(current_state) #drop off passenger 卸载乘客

    #返回车库(发生在最后一次卸载乘客10分钟后)
    current_state=taxi.send(current_state.time+10)
    print(current_state) #going home 返回车库

    try:
        current_state=taxi.send(current_state.time+1)
        print(current_state)
    except StopIteration as e:
        print('此时出租车协程执行完毕,抛出StopInteration')

"""
执行:
    main_01()
    
输出结果如下:

    Event(time=0, proc=13, action='level garage')
    Event(time=7, proc=13, action='pick up passenger')
    Event(time=30, proc=13, action='drop off passenger')
    Event(time=35, proc=13, action='pick up passenger')
    Event(time=83, proc=13, action='drop off passenger')
    Event(time=93, proc=13, action='going home')
    此时出租车协程执行完毕,抛出StopInteration
"""

#出租车模拟类
import random

class Simulator:
    #计算指定aciton到下一个action之间的耗时
    def compute_duration(self,previous_action):
        if previous_action=='drop off passenger':
            return random.choice([1,2])
        elif previous_action=='pick up passenger':
            return random.choice([7,8])
        elif previous_action=='level garage':
            return random.choice([10,15])
        elif previous_action=='going home':
            return random.choice([20,30])
        else:
            raise Exception('Unknown Previoud_Action')

    def __init__(self,procs_dict):
        self.events=PriorityList()
        self.procs=procs_dict

    #仿真系统主逻辑
    def run(self,end_time):
        #预激每一个出租车协程
        for _,proc in self.procs.items():
            #每个出租车协程的第一个事件
            first_event=proc.send(None) #预激
            #将每个出租车协程的第一个事件放入事件列表
            self.events.add_list(first_event)


        #这个仿真系统的事件主循环
        sim_time=0
        #遍历并处理每个事件
        while sim_time<end_time:#判断运行时间是否超时
            #事件列表为空,所有事件执行完毕
            if self.events.is_empty():
                print('******** end all events ********')
                return

            current_event=self.events.get_first() #获取事件列表中最早发生的事件

            #处理当前事件(此处用打印来模拟处理过程)
            sim_time,proc_id,previous_action=current_event
            print('taxi:',proc_id,proc_id*'    ',current_event) #打印当前事件
            #从事件标记列表中移除已处理过的事件
            self.events.del_list(current_event)

            active_proc=self.procs[proc_id] #获取这个事件所属的出租车协程
            next_time=sim_time+self.compute_duration(previous_action) #计算下一个事件的发生时间

            try:
                next_event=active_proc.send(next_time) #向出租车协程发送参数(参数表示下次事件发生的时间)
            except StopIteration:
                #如果触发这个异常表示出租车协程执行完毕
                del self.procs[proc_id]
            else:
                #将新事件添加到事件列表
                self.events.add_list(next_event)
        else:
            #执行时间超时后的处理
            print('---->执行超时<----')


#测试出租车协程能否正常执行
def main_02():
    data_dict={
        1:taxi_process(ident=1,trips=3,start_time=0),
        2:taxi_process(ident=2,trips=4,start_time=30),
        3:taxi_process(ident=3,trips=2,start_time=13),
    }

    sim1=Simulator(data_dict)
    sim1.run(100) #时间足够执行完成所有的出租车协程

'''
执行:
    main_02()
输出结果:
    taxi: 1      Event(time=0, proc=1, action='level garage')
    taxi: 1      Event(time=10, proc=1, action='pick up passenger')
    taxi: 3              Event(time=13, proc=3, action='level garage')
    taxi: 1      Event(time=17, proc=1, action='drop off passenger')
    taxi: 1      Event(time=18, proc=1, action='pick up passenger')
    taxi: 1      Event(time=26, proc=1, action='drop off passenger')
    taxi: 3              Event(time=28, proc=3, action='pick up passenger')
    taxi: 1      Event(time=28, proc=1, action='pick up passenger')
    taxi: 2          Event(time=30, proc=2, action='level garage')
    taxi: 1      Event(time=35, proc=1, action='drop off passenger')
    taxi: 3              Event(time=36, proc=3, action='drop off passenger')
    taxi: 1      Event(time=37, proc=1, action='going home')
    taxi: 3              Event(time=38, proc=3, action='pick up passenger')
    taxi: 2          Event(time=40, proc=2, action='pick up passenger')
    taxi: 3              Event(time=46, proc=3, action='drop off passenger')
    taxi: 2          Event(time=47, proc=2, action='drop off passenger')
    taxi: 3              Event(time=48, proc=3, action='going home')
    taxi: 2          Event(time=48, proc=2, action='pick up passenger')
    taxi: 2          Event(time=56, proc=2, action='drop off passenger')
    taxi: 2          Event(time=57, proc=2, action='pick up passenger')
    taxi: 2          Event(time=64, proc=2, action='drop off passenger')
    taxi: 2          Event(time=66, proc=2, action='pick up passenger')
    taxi: 2          Event(time=74, proc=2, action='drop off passenger')
    taxi: 2          Event(time=75, proc=2, action='going home')
    ******** end all events ********
'''

#测试设置超时时间是否有效
def main_03():
    data_dict={
        1:taxi_process(ident=1,trips=3,start_time=0),
        2:taxi_process(ident=2,trips=4,start_time=30),
        3:taxi_process(ident=3,trips=2,start_time=13),
    }

    sim1=Simulator(data_dict)
    sim1.run(30) #时间不足以执行完成所有的出租车协程
'''
执行
    main_03()
输出结果:
    taxi: 1      Event(time=0, proc=1, action='level garage')
    taxi: 3              Event(time=13, proc=3, action='level garage')
    taxi: 1      Event(time=15, proc=1, action='pick up passenger')
    taxi: 1      Event(time=22, proc=1, action='drop off passenger')
    taxi: 3              Event(time=23, proc=3, action='pick up passenger')
    taxi: 1      Event(time=23, proc=1, action='pick up passenger')
    taxi: 2          Event(time=30, proc=2, action='level garage')
    taxi: 3              Event(time=30, proc=3, action='drop off passenger')
    taxi: 1      Event(time=30, proc=1, action='drop off passenger')
    ---->执行超时<---- 
'''

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容