【SimPy系列博客之官方example学习与解读】—— Example 4: Event Latency

这篇具有很好参考价值的文章主要介绍了【SimPy系列博客之官方example学习与解读】—— Example 4: Event Latency。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Hello,CSDN的各位小伙伴们,又见面啦!今天我们要学习的例程是:Event Latency!我们开始吧!

例程背景

今天这个example比较好玩,有点类似于网络中的通信。我们要实现的是一个简单的point-to-point的消息收发机制。其中,sender源源不断地通过电缆cable给另一端的receiver发送消息,然而消息在电缆中的传输是有延迟的,因此我们还需要模拟这一种延迟。而我们需要思考的则是如何把这种延迟的建模和收发双发的processes分离开

例程代码分析

我们跳过基本的头文件和参数设置:

import simpy

SIM_DURATION = 100

接下来,我们对电缆进行建模,我们思考一下电缆cable类中需要有什么功能呢?第一个我们能够发送消息到电缆上;第二,能够模拟消息传输过程中的延迟;第三,接收方能够从电缆上获取数据。为了实现功能1、3,我们就需要使用simpy中的store资源了:

class Cable:
    def __init__(self, env, delay):
        self.env = env
        self.delay = delay
        self.store = simpy.Store(env)

    def latency(self, value):
        yield self.env.timeout(self.delay)  # 模拟传输过程中的时延
        self.store.put(value)  # 向电缆中传输数据

    def put(self, value):
        self.env.process(self.latency(value))

    def get(self):
        return self.store.get()  # 从电缆中获取数据

基本上比较重要的点都在注释上了,但是还有一个特别值得关注的是:在latency函数中,yield self.env.timeout(self.delay)self.store.put(value)这两句的顺序是不能调换的。不然就无法体现延迟的效果。

接下来,我们来看看收发双方怎么写:

def sender(env, cable):
    while True:
        yield env.timeout(5)  # 表示每隔多久发包一次
        cable.put(f'Sender sent this message at {env.now}')

收方:

def receiver(env, cable):
    while True:
        msg = yield cable.get()  # 注意要有 "yield"
        print('Receive the message: { ', msg, ' } at: ', env.now)

最后启动仿真,如下:

print('EXAMPLE 4: EVENT LATENCY')
env = simpy.Environment()
cable = Cable(env, 10)
env.process(sender(env, cable))
env.process(receiver(env, cable))
env.run(until=SIM_DURATION)

输出的效果为:

EXAMPLE 4: EVENT LATENCY
Receive the message: {  Sender sent this message at 5  } at:  15
Receive the message: {  Sender sent this message at 10  } at:  20
Receive the message: {  Sender sent this message at 15  } at:  25
Receive the message: {  Sender sent this message at 20  } at:  30
Receive the message: {  Sender sent this message at 25  } at:  35
Receive the message: {  Sender sent this message at 30  } at:  40
Receive the message: {  Sender sent this message at 35  } at:  45
Receive the message: {  Sender sent this message at 40  } at:  50
Receive the message: {  Sender sent this message at 45  } at:  55
Receive the message: {  Sender sent this message at 50  } at:  60
Receive the message: {  Sender sent this message at 55  } at:  65
Receive the message: {  Sender sent this message at 60  } at:  70
Receive the message: {  Sender sent this message at 65  } at:  75
Receive the message: {  Sender sent this message at 70  } at:  80
Receive the message: {  Sender sent this message at 75  } at:  85
Receive the message: {  Sender sent this message at 80  } at:  90
Receive the message: {  Sender sent this message at 85  } at:  95

其实在这个例子中,我们相当于用一个store作为中介,来完成数据的收发。

扩展

扩展1

在上面的例子中,sender仅仅是向cable发送了一个字符串消息,如果在其他场景中,sender的一次消息中需要包含很多其他信息,要怎做呢?—— 我们可以将一个tuple put到store中,我们只需要适当修改sender和receiver函数:

def sender(env, cable):
    while True:
        yield env.timeout(5)  # 表示每隔多久发包一次
        cable.put(('Message!', env.now))

def receiver(env, cable):
    while True:
        msg = yield cable.get()
        print('Receive the message: { ', msg[0], ' }, sending at: ', msg[1], ' at: ', env.now)

结果如下:

EXAMPLE 4: EVENT LATENCY
Receive the message: {  Message!  }, sending at:  5  at:  15
Receive the message: {  Message!  }, sending at:  10  at:  20
Receive the message: {  Message!  }, sending at:  15  at:  25
Receive the message: {  Message!  }, sending at:  20  at:  30
Receive the message: {  Message!  }, sending at:  25  at:  35
Receive the message: {  Message!  }, sending at:  30  at:  40
Receive the message: {  Message!  }, sending at:  35  at:  45
Receive the message: {  Message!  }, sending at:  40  at:  50
Receive the message: {  Message!  }, sending at:  45  at:  55
Receive the message: {  Message!  }, sending at:  50  at:  60
Receive the message: {  Message!  }, sending at:  55  at:  65
Receive the message: {  Message!  }, sending at:  60  at:  70
Receive the message: {  Message!  }, sending at:  65  at:  75
Receive the message: {  Message!  }, sending at:  70  at:  80
Receive the message: {  Message!  }, sending at:  75  at:  85
Receive the message: {  Message!  }, sending at:  80  at:  90
Receive the message: {  Message!  }, sending at:  85  at:  95

扩展2

上面的这些例子都还是只是最简单的P2P网络,我们现在考虑一对多的通信情况:其中,有一个sender,若干个receiver,sender不停的向receiver发送消息,只不过每次消息所要发给的对象不同,有的message是发给receiver 1的,有的消息是发给receiver 2的…,message经过电缆的传输延迟后,由对应的receiver进行接收。这是一个更加复杂的情况,我们来分析一下如何写出代码。

首先,cable类我们无需改动,但是需要将sender和receiver用类的形式进行改写:

class Receiver:
    def __init__(self, env, id, cable):
        self.env = env
        self.id = id  # 用来指示不同的receiver
        self.cable = cable

    def receive(self):
        msg = yield self.cable.get()
        print('Receiver: ', self.id, ' receives the message: { ', msg[0], ' }, sending at: ',
              msg[1], ' for: ', msg[2], ' at: ', env.now)

值得注意的是,目前receive函数还没有被加入到env.process()中,所以如果此时实例化该类,再启动仿真,是没有任何结果的。

接下来,我们看看sender类:

class Sender:
    def __init__(self, env, id, cable):
        self.env = env
        self.id = id  # 用来指示不同的sender
        self.cable = cable
        self.process = None

    def send(self, number_of_receiver, receivers):
        while True:  # sender会一直持续发包
            yield self.env.timeout(5)  # 表示每隔多久发包一次
            
            dst_id = random.randint(0, number_of_receiver-1)  # 先随机选择一个receiver
            self.cable.put(('Message!', self.env.now, dst_id))  # 向该receiver发包
            self.process = self.env.process(receivers[dst_id].receive())

这里,我们对self.process = self.env.process(receivers[dst_id].receive())进行解释:sender在发完包之后,如果让对应的receiver能够接收到呢?我们可以直接在sender处启动对应receiver的receive()函数。receivers是一个列表,里面的元素表示每一个receiver类,dst_id表示该message是发给哪一个receiver的,因此receivers[dst_id]就表示对应的receiver类,然后将这个receive()函数加入到仿真环境中,就可以让对应的接收方从cable中取出该message。

还需要注意的是,我们虽然在send函数中,将对应receiver的接收函数加入到了env.process()中,但是send函数本身还没有加入,因此在实例化Sender后,需要把send()加到仿真环境中:

print('EXAMPLE 4: EVENT LATENCY')
random.seed(2024)
env = simpy.Environment()
cable = Cable(env, 10)

# 先创建receiver
receivers = []
for i in range(NUMBER_OF_RECEIVERS):
    r = Receiver(env, i, cable)
    receivers.append(r)

# 创建一个sender
s = Sender(env, 9999, cable)
env.process(s.send(NUMBER_OF_RECEIVERS, receivers))
env.run(until=SIM_DURATION)

仿真结果如下:

EXAMPLE 4: EVENT LATENCY
Receiver:  1  receives the message: {  Message!  }, sending at:  5  for:  1  at:  15
Receiver:  0  receives the message: {  Message!  }, sending at:  10  for:  0  at:  20
Receiver:  2  receives the message: {  Message!  }, sending at:  15  for:  2  at:  25
Receiver:  2  receives the message: {  Message!  }, sending at:  20  for:  2  at:  30
Receiver:  1  receives the message: {  Message!  }, sending at:  25  for:  1  at:  35
Receiver:  0  receives the message: {  Message!  }, sending at:  30  for:  0  at:  40
Receiver:  2  receives the message: {  Message!  }, sending at:  35  for:  2  at:  45
Receiver:  1  receives the message: {  Message!  }, sending at:  40  for:  1  at:  50
Receiver:  2  receives the message: {  Message!  }, sending at:  45  for:  2  at:  55
Receiver:  1  receives the message: {  Message!  }, sending at:  50  for:  1  at:  60
Receiver:  2  receives the message: {  Message!  }, sending at:  55  for:  2  at:  65
Receiver:  0  receives the message: {  Message!  }, sending at:  60  for:  0  at:  70
Receiver:  2  receives the message: {  Message!  }, sending at:  65  for:  2  at:  75
Receiver:  2  receives the message: {  Message!  }, sending at:  70  for:  2  at:  80
Receiver:  1  receives the message: {  Message!  }, sending at:  75  for:  1  at:  85
Receiver:  1  receives the message: {  Message!  }, sending at:  80  for:  1  at:  90
Receiver:  1  receives the message: {  Message!  }, sending at:  85  for:  1  at:  95

我们可以看到,结果符合我们的要求。

扩展3

有了前面的一系列铺垫,我们很容易能够将我们的整个通信系统扩展到多对多:即多个sender给多个receiver分别发消息,下面直接贴上完整代码,应该是没有太多困难的地方了:

import simpy
import random

RANDOM_SEED = 2024
NUMBER_OF_RECEIVERS = 3
SIM_DURATION = 100

class Cable:
    def __init__(self, env, delay):
        self.env = env
        self.delay = delay
        self.store = simpy.Store(env)

    def latency(self, value):
        yield self.env.timeout(self.delay)
        self.store.put(value)

    def put(self, value):
        self.env.process(self.latency(value))

    def get(self):
        return self.store.get()

class Receiver:
    def __init__(self, env, id, cable):
        self.env = env
        self.id = id
        self.cable = cable

    def receive(self):
        msg = yield self.cable.get()
        print('Receiver: ', self.id, ' receives the message: { ', msg[0], ' }, sending at: ',
              msg[1], 'from: ', msg[2], ' for: ', msg[3], ' at: ', env.now)

class Sender:
    def __init__(self, env, id, cable):
        self.env = env
        self.id = id
        self.cable = cable
        self.process = None

    def send(self, number_of_receiver, receivers):
        while True:  # sender持续发包
            yield self.env.timeout(5)  # 表示每隔多久发包一次
            # 先随机选择一个receiver
            dst_id = random.randint(0, number_of_receiver-1)
            self.cable.put(('Message!', self.env.now, self.id, dst_id))
            self.process = self.env.process(receivers[dst_id].receive())

print('EXAMPLE 4: EVENT LATENCY')
random.seed(RANDOM_SEED)
env = simpy.Environment()
cable = Cable(env, 10)

# 先创建receiver
receivers = []
for i in range(NUMBER_OF_RECEIVERS):
    r = Receiver(env, i, cable)
    receivers.append(r)

# 创建一个sender
for j in range(3):
    x = Sender(env, j+1000, cable)
    env.process(x.send(NUMBER_OF_RECEIVERS, receivers))
    
env.run(until=SIM_DURATION)

仿真结果如下:

EXAMPLE 4: EVENT LATENCY
Receiver:  1  receives the message: {  Message!  }, sending at:  5 from:  1000  for:  1  at:  15
Receiver:  0  receives the message: {  Message!  }, sending at:  5 from:  1001  for:  0  at:  15
Receiver:  2  receives the message: {  Message!  }, sending at:  5 from:  1002  for:  2  at:  15
Receiver:  2  receives the message: {  Message!  }, sending at:  10 from:  1000  for:  2  at:  20
Receiver:  1  receives the message: {  Message!  }, sending at:  10 from:  1001  for:  1  at:  20
Receiver:  0  receives the message: {  Message!  }, sending at:  10 from:  1002  for:  0  at:  20
Receiver:  2  receives the message: {  Message!  }, sending at:  15 from:  1000  for:  2  at:  25
Receiver:  1  receives the message: {  Message!  }, sending at:  15 from:  1001  for:  1  at:  25
Receiver:  2  receives the message: {  Message!  }, sending at:  15 from:  1002  for:  2  at:  25
Receiver:  1  receives the message: {  Message!  }, sending at:  20 from:  1000  for:  1  at:  30
Receiver:  2  receives the message: {  Message!  }, sending at:  20 from:  1001  for:  2  at:  30
Receiver:  0  receives the message: {  Message!  }, sending at:  20 from:  1002  for:  0  at:  30
Receiver:  2  receives the message: {  Message!  }, sending at:  25 from:  1000  for:  2  at:  35
Receiver:  2  receives the message: {  Message!  }, sending at:  25 from:  1001  for:  2  at:  35
Receiver:  1  receives the message: {  Message!  }, sending at:  25 from:  1002  for:  1  at:  35
Receiver:  1  receives the message: {  Message!  }, sending at:  30 from:  1000  for:  1  at:  40
Receiver:  1  receives the message: {  Message!  }, sending at:  30 from:  1001  for:  1  at:  40
Receiver:  2  receives the message: {  Message!  }, sending at:  30 from:  1002  for:  2  at:  40
Receiver:  2  receives the message: {  Message!  }, sending at:  35 from:  1000  for:  2  at:  45
Receiver:  2  receives the message: {  Message!  }, sending at:  35 from:  1001  for:  2  at:  45
Receiver:  0  receives the message: {  Message!  }, sending at:  35 from:  1002  for:  0  at:  45
Receiver:  1  receives the message: {  Message!  }, sending at:  40 from:  1000  for:  1  at:  50
Receiver:  2  receives the message: {  Message!  }, sending at:  40 from:  1001  for:  2  at:  50
Receiver:  2  receives the message: {  Message!  }, sending at:  40 from:  1002  for:  2  at:  50
Receiver:  1  receives the message: {  Message!  }, sending at:  45 from:  1000  for:  1  at:  55
Receiver:  2  receives the message: {  Message!  }, sending at:  45 from:  1001  for:  2  at:  55
Receiver:  0  receives the message: {  Message!  }, sending at:  45 from:  1002  for:  0  at:  55
Receiver:  2  receives the message: {  Message!  }, sending at:  50 from:  1000  for:  2  at:  60
Receiver:  0  receives the message: {  Message!  }, sending at:  50 from:  1001  for:  0  at:  60
Receiver:  2  receives the message: {  Message!  }, sending at:  50 from:  1002  for:  2  at:  60
Receiver:  2  receives the message: {  Message!  }, sending at:  55 from:  1000  for:  2  at:  65
Receiver:  1  receives the message: {  Message!  }, sending at:  55 from:  1001  for:  1  at:  65
Receiver:  2  receives the message: {  Message!  }, sending at:  55 from:  1002  for:  2  at:  65
Receiver:  2  receives the message: {  Message!  }, sending at:  60 from:  1000  for:  2  at:  70
Receiver:  0  receives the message: {  Message!  }, sending at:  60 from:  1001  for:  0  at:  70
Receiver:  2  receives the message: {  Message!  }, sending at:  60 from:  1002  for:  2  at:  70
Receiver:  0  receives the message: {  Message!  }, sending at:  65 from:  1000  for:  0  at:  75
Receiver:  1  receives the message: {  Message!  }, sending at:  65 from:  1001  for:  1  at:  75
Receiver:  0  receives the message: {  Message!  }, sending at:  65 from:  1002  for:  0  at:  75
Receiver:  1  receives the message: {  Message!  }, sending at:  70 from:  1000  for:  1  at:  80
Receiver:  2  receives the message: {  Message!  }, sending at:  70 from:  1001  for:  2  at:  80
Receiver:  1  receives the message: {  Message!  }, sending at:  70 from:  1002  for:  1  at:  80
Receiver:  1  receives the message: {  Message!  }, sending at:  75 from:  1000  for:  1  at:  85
Receiver:  0  receives the message: {  Message!  }, sending at:  75 from:  1001  for:  0  at:  85
Receiver:  2  receives the message: {  Message!  }, sending at:  75 from:  1002  for:  2  at:  85
Receiver:  2  receives the message: {  Message!  }, sending at:  80 from:  1000  for:  2  at:  90
Receiver:  0  receives the message: {  Message!  }, sending at:  80 from:  1001  for:  0  at:  90
Receiver:  1  receives the message: {  Message!  }, sending at:  80 from:  1002  for:  1  at:  90
Receiver:  1  receives the message: {  Message!  }, sending at:  85 from:  1000  for:  1  at:  95
Receiver:  1  receives the message: {  Message!  }, sending at:  85 from:  1001  for:  1  at:  95
Receiver:  1  receives the message: {  Message!  }, sending at:  85 from:  1002  for:  1  at:  95

最后,特别需要注意的是:要想实现多对多,或者一对多通信,那么这个cable一定要是在外部设的,而不能是sender类或者是receiver类里面自己重新初始化的成员!文章来源地址https://www.toymoban.com/news/detail-791547.html

到了这里,关于【SimPy系列博客之官方example学习与解读】—— Example 4: Event Latency的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【人脸检测——Dlib学习1】Face_detector_example

    # -*-coding:utf-8-*- #author: lyp time: 2018/9/7 import cv2 import dlib # 初始化程序 detector = dlib.get_frontal_face_detector() # 读取图片,在cmd中键入 python xx(文件名).py 需要识别的图片名 img = cv2.imread(\\\"cba.jpg\\\") # 参数1表示我们对图像进行向上采样1倍,这将使一切变的更大 # 进而让我们检测出更多的

    2024年02月10日
    浏览(58)
  • 学习/cmake-cookbook/chapter-01/recipe-07/example

    代码链接:cmake-cookbook/chapter-01/recipe-07/example at master · dev-cafe/cmake-cookbook · GitHub BUG 是告诉如G++之类的编译器在每个translation unit中定义macro NDEBUG,进而导致所有assert()都被关闭!合法取值是Debug,Release,RelWithDebInfo,MinSizeRel;,其中CONFIG就是上述构建类型名称的大写,因为我

    2023年04月16日
    浏览(31)
  • 【ros2 control 机器人驱动开发】简单双关节机器人学习-example 1

    【ros2 control 机器人驱动开发】简单双关节机器人学习-example 1 本系列文件主要有以下目标和内容: 为系统、传感器和执行器创建 HardwareInterface 以URDF文件的形式创建机器人描述 加载配置并使用启动文件启动机器人 控制RRBot的两个关节(两旋转关节机器人) 六自由度机器人的

    2024年02月04日
    浏览(59)
  • Flutter 添加 example流程

    一、已有Flutter工程(命令)添加 example 1、cd 工程(flutter_plugin ,是自己创建的)根目录       例: flutter create example  执行命令创建example PS:cd example 后执行flutter doctor 后就可以看到效果 2、如果需要指定iOS/Android 语言,请添加 \\\"-i  / -a\\\" 参数      例: flutter create -i objc -a kotlin

    2024年02月15日
    浏览(43)
  • Spring Boot Kafka Example

    作者:禅与计算机程序设计艺术 Kafka是一个分布式消息系统,它可以实现消息的持久化、高并发量处理以及实时的可靠传输。相比于其他消息队列中间件(例如RabbitMQ、ActiveMQ),其最大的优点在于它提供的跨越语言的API支持,支持多种编程语言的客户端。作为一种轻量级的分

    2024年02月07日
    浏览(45)
  • ListenableFuture和countdownlatch使用example

    ListenableFuture可以允许你注册回调方法(callbacks),在运算(多线程执行)完成的时候进行调用, 或者在运算(多线程执行)完成后立即执行

    2024年02月07日
    浏览(49)
  • Qt Example各例子技术点说明(六)

    说明: 下面的XX.XX.XX为Qt的版本号,如:5.14.1。 下面总结的都是以Qt的5.14.1版本来说明的,未来的版本也许和这有些不同。 因为Qt自带的例子很多,本博文是第6部分,第1、2、3、4、5部分请参见如下链接: 《Qt Example各例子技术点说明(一)》。 《Qt Example各例子技术点说明(

    2024年02月11日
    浏览(28)
  • 在langchain中使用自定义example selector

    在langchain中使用自定义example selector 在之前的文章中,我们提到了可以在跟大模型交互的时候,给大模型提供一些具体的例子内容,方便大模型从这些内容中获取想要的答案。这种方便的机制在langchain中叫做FewShotPromptTemplate。 如果例子内容少的话,其实无所谓,我们可以把所

    2024年02月13日
    浏览(46)
  • 无涯教程-Android - Style Demo Example函数

    下面的示例演示如何将样式用于单个元素。让我们开始按照以下步骤创建一个简单的Android应用程序- 步骤 说明 1 您将使用Android Studio IDE创建一个Android应用程序,并在 com.example.saira_000.myapplication 包下将其命名为 myapplication ,如中所述您好世界Example一章。 2 修改 src/MainActivity.jav

    2024年02月10日
    浏览(34)
  • 【论文笔记 】EOT算法:Synthesizing robust adversarial example

    对于基于神经网络的分类器,对抗样本是一种加入了微小扰动的样本,能够让分类器产生错误的判断从而识别失败。传统的二维对抗样本通过打印等方式转移导现实世界中时,在有限的视角下能够保持对抗性。但在复杂多变的实际应用场景中,受光照、视角偏移和相机噪声等

    2024年01月20日
    浏览(62)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包