资讯专栏INFORMATION COLUMN

流畅的python:出租车仿真示例

darkbaby123 / 2259人阅读

摘要:仿真示例出租车进程。每次状态变化时向仿真程序产出一个事件结束出租车进程出租车仿真程序主程序。

这个简单的例子让我们比较浅显易懂的看到了事件驱动型框架的运作方式,即在单个线程中使用一个主循环驱动协程执行并发活动。

使用协程做面向事件编程时,协程会不断的把控制权让步给主循环,激活并向前运行其他协程,从而执行各个并发活动。这是一种协作多任务:协程显示的把控制权让步给中央调度程序。

仿真示例

import random
import collections
import queue
import argparse
import time

DEFAULT_NUMBER_OF_TAXIS = 3
DEFAULT_END_TIME = 180
SEARCH_DURATION = 5
TRIP_DURATION = 20
DEPARTURE_INTERVAL = 5

Event = collections.namedtuple("Event", "time proc action")

#出租车进程。
def taxi_process(ident, trips, start_time=0):
    """每次状态变化时向仿真程序产出一个事件"""
    time = yield Event(start_time, ident, "leave 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")
    #结束出租车进程

#出租车仿真程序主程序。
class Simulator:

    def __init__(self, procs_map):
        self.events = queue.PriorityQueue()  #优先级队列,put方法放入数据,一般是一个数组(3, someting),get()方法数值小的优先出队
        self.procs = dict(procs_map)  #创建字典的副本

    def run(self, end_time):
        """调度并显示事件,直到事件结束"""
        #调度各辆出租车的第一个事件
        for _, proc in sorted(self.procs.items()):
            first_event = next(proc)  #第一个事件是所有车离开车库,也是为了激活子生成器
            self.events.put(first_event)  #所有车的第一个事件放到优先队列中,time小的优先出来

        #此次仿真的主循环
        sim_time = 0
        while sim_time < end_time:
            if self.events.empty():
                print("***事件结束***")
                break
            current_event = self.events.get() #取出time最小的事件
            sim_time, proc_id, previous_action = current_event  #元组解包
            print("taxi:", proc_id, proc_id * "  ", current_event)
            active_proc = self.procs[proc_id]  #取出当前事件对象。是一个子生成器对象,下面要对这个对象send(time)来获得下一个yield的返回值
            next_time = sim_time + comput_duration(previous_action)  #随机计算下一个时间
            try:
                next_event = active_proc.send(next_time)  #下一个事件是子生成器执行到下一个yield的返回值
            except StopIteration:  #StopIteration异常说明当前子生成器执行完毕,从字典中删除它
                del self.procs[proc_id]
            else:
                self.events.put(next_event) #否则就把下一个事件放入优先队列中
        else: #如果while循环没有以break结束,那么输出结束信息
            msg = "*** 仿真结束。{}个车没有回家 ***"
            print(msg.format(self.events.qsize()))
        #仿真结束

def comput_duration(previous_action):
    """使用指数分布计算操作的耗时"""
    if previous_action in ["leave garage", "drop off passenger"]:
        interval = SEARCH_DURATION
    elif previous_action == "pick up passenger":
        #新状态是行程开始
        interval = TRIP_DURATION
    elif previous_action == "going home":
        interval = 1
    else:
        raise ValueError("未知的活动:{}".format(previous_action))
    return int(random.expovariate(1/interval) + 1)

def main(end_time=DEFAULT_END_TIME, num_taxis=DEFAULT_NUMBER_OF_TAXIS, seed=None):
    #构建随机生成器,构建过程,运行仿真程序
    if seed is not None:
        random.seed(seed)  #指定seed的值时,用这个seed可以使随机数随机出来的相等
    taxis = {i: taxi_process(i, (i+1*2), i*DEPARTURE_INTERVAL) for i in range(num_taxis)} #字典生成式,生成指定数量的子生成器对象
    sim = Simulator(taxis) #实例化仿真主循环
    sim.run(end_time)  #run it!

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="出租车运行仿真")  #创建参数解析对象,添加描述
    parser.add_argument("-e", "--end_time", type=int, default=DEFAULT_END_TIME) #添加-e参数,默认值为180
    parser.add_argument("-t", "--taxis", type=int, default=DEFAULT_NUMBER_OF_TAXIS, help="出租车出行数量, default=%s" %DEFAULT_NUMBE
R_OF_TAXIS)  #添加-t参数,用来指定出租车数量,默认值为3
    parser.add_argument("-s", "--seed", type=int, default=None, help="随机生成seed")  #添加-s参数,用来设置seed值,如果seed值一样那
么随机出来的结果也会一样,默认值为None
    args = parser.parse_args()  #这个函数用来获取参数
    main(args.end_time, args.taxis, args.seed) #通过上面函数的属性的到输入的参数,属性可以是双横线后的字符串也可以是添加参数函数的第一个不加横线的字符串


文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/43773.html

相关文章

  • python协程3:用仿真实验学习协程

    摘要:徘徊和行程所用的时间使用指数分布生成,我们将时间设为分钟数,以便显示清楚。迭代表示各辆出租车的进程在各辆出租车上调用函数,预激协程。 前两篇我们已经介绍了python 协程的使用和yield from 的原理,这一篇,我们用一个例子来揭示如何使用协程在单线程中管理并发活动。。 什么是离散事件仿真 Wiki上的定义是: 离散事件仿真将系统随时间的变化抽象成一系列的离散时间点上的事件,通过...

    banana_pi 评论0 收藏0
  • “驾驶脑”上云,同济大学智能无人车实现L4高自动驾驶

    摘要:年来,途灵智能无人车实验室一直致力于研发级全自动驾驶系统。目前,同济大学途灵智能无人车实验室正在攻克的课题就是提高级自动驾驶技术突破环境局限的能力,这种突破需要将驾驶脑放置在仿真模拟场景下进行大量的极限训练。车水马龙的道路上,各种车辆交错汇聚,各种道路状况频出。从行驶缓慢的环卫车到疾驶抢道的出租车、因施工临时封闭的道路、突发的交通事故现场。作为路面上的车辆,是互不相让,还是借道通过,又或者是...

    Tecode 评论0 收藏0
  • Xamarin 学习笔记

    摘要:自此微软生成用开发的软件将不仅仅能够运行在上,而是可以在任何设备上运行。 本文翻译自CodeProject文章:https://www.codeproject.com/Articles/1223980/Xamarin-Notes-Set-up-the-environment-Windows-and-I 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。...

    keithxiaoy 评论0 收藏0
  • 华为云推出三款基于鲲鹏芯片ARM云服务

    摘要:近日,华为宣布推出业界最高性能处理器鲲鹏,以及基于鲲鹏的服务器。弹性云服务器灵活弹性,性能领先倍华为云将推出基于的弹性云服务器,相较于业界同类规格云服务器性能领先倍。近日,华为宣布推出业界最高性能ARM-based处理器-鲲鹏920(Kunpeng 920),以及基于鲲鹏 920 的TaiShan服务器。TaiShan服务器目前已经率先应用在华为云上,以服务的形式提供弹性云服务器、裸金属服务...

    z2xy 评论0 收藏0
  • python大数据可视化pygal仿真模拟摇筛子完成实例

      本文关键为大家分享了python大数据可视化pygal仿真模拟摇筛子完成实例,感兴趣的小伙伴可以参考借鉴一下,希望可以有一定的帮助,祝愿大家多多的不断进步,尽早涨薪  数据可视化包Pygal形成可放大矢量图格式文档  还可以在规格不同类型的屏上全自动放大,表明数据图表  #安装pygal   pipinstallpygal   '''   想要了解Pygal可生成什么样...

    89542767 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<