AnyMath 文档
Notebook

Wi-Fi网络的离散事件模型

该模型模拟具有有限数量的并行通道的路由器和产生网络流量的多个客户端设备的操作。 该模拟器演示了无线网络的基本原理,包括资源竞争、排队和信道加载动态
.\我们模型的主要元素如下所述。 结构 **Событие**它是离散事件模型的基本要素,表示系统中在特定时间发生的单独事件。 它存储四个主要属性。 领域 время 它包含一个时间戳,指示事件何时应该发生在条件模拟单元中,它允许调度程序按时间顺序排列事件。 领域 тип 使用符号定义事件类别,例如 :генерация_запроса, :запрос:конец_передачи,这决定了应该调用哪个处理函数。 领域 устройство 通过存储特定客户端设备的字符串标识符(例如,"Laptop_1"),将事件绑定到其源或接收者。 最后,场 данные 它旨在以命名字段的元组或另一类型的形式存储与事件相关的任何附加信息;例如,对于请求事件,唯一的请求标识符及其创建时间可以存储在这里。 这种结构是不可变的,这保证了在整个仿真过程中创建事件数据后的完整性。

结构 **Устройство**模拟Wi-Fi网络上的客户端硬件,如笔记本电脑或智能手机。 它是可变的,因为它的状态必须在模拟期间更新。 该结构包括三个字段。 领域 имя 它包含设备的唯一字符串标识符,例如"Smartphone_2",用于将事件和请求与其源相关联。 领域 интенсивность 通过存储连续数据请求生成之间的平均时间(以条件模拟单位)来确定设备的行为;这个数字越低,设备在网络上创建负载的频率就越高。 领域 счетчик_запросов 它跟踪自模拟开始以来此设备生成的请求总数;该值随着每个新请求而递增,通常用于为这些请求生成唯一标识符。

结构 **Роутер**表示资源有限的Wi-Fi热点模型。 这是一个多变的结构,因为通道和队列的状态不断变化。 它包括三个字段。 领域 каналы 通过存储一个整数来定义路由器的最大带宽,该整数指示可用于同时数据传输的并行连接或通道数(例如,2)。 领域 занятые_каналы 跟踪当前负载,显示当前有多少可用信道正忙于处理数据传输。 领域 очередь 它是一个字符串向量(Vector{String}),其中每个字符串是来自试图开始传输但所有通道都忙的设备的请求的标识符(例如,"笔记本电脑_1-03");这个向量实现了FIFO(先进先出)逻辑,其中第一个传入的请求将在队列中提供服务。 该结构有一个构造函数 Роутер(каналы::Int) 其中,在创建新对象时,自动将占用的通道数初始化为零,并创建空队列,确保模型的正确初始状态。

结构 **ПланировщикСобытий**它是离散事件模拟引擎的核心,负责管理所有操作的时间和顺序。 这是一个可变的结构。 它包含两个字段。 领域 события 它是所有计划但尚未处理的事件的按时间顺序排列的集合,存储为结构的向量。 Событие. 为了在时间上有效地提取下一个事件,向量保持在时间排序状态,这允许您从向量的末尾快速提取最早的事件。 领域 текущее_время 它存储仿真进展到的虚拟时间点;每次检索和处理新事件时都会更新该值,并作为整个模型的全局时钟。 该结构有一个构造函数 ПланировщикСобытий(),其初始化空事件列表并将初始模拟时间设置为0.0。 主模拟循环不断地请求调度程序的下一个事件,更新 текущее_время 在该事件发生时,并将该事件传送给适当的功能进行处理,从而模拟系统中的时间流逝。

In [ ]:
结构事件
    时间::Float64
    类型::符号
    设备::字符串
    数据::任何
end

可变结构装置
    名称::字符串
    强度:浮64
    counter_query::Int
end

可变结构路由器
    频道::Int
    繁忙频道::Int
    队列::向量{字符串}
    
    功能路由器(通道::Int)
        (通道,0,字符串[])
    end
end

事件调度器的可变结构
    事件::向量{事件}
    当前时间::Float64
    
    事件调度函数()
        (事件[],0.0)
    end
end

功能 добавить_событие! 在调度程序中放置一个新事件,并以相反的顺序按时间对整个列表进行排序,确保最早的事件始终位于向量的末尾。 功能 следующее_событие 从向量的末尾检索并返回此最早的事件,如果列表为空,则返回 nothing,其信号模拟结束。

In [ ]:
function_包含事件!(策划者::活动策划者,活动::活动)
    推!(策划者。事件,事件)
    排序!(策划者。事件,by=x->x.time,rev=true
end

下一个事件功能(scheduler::Event Planner)
    isempty(scheduler.事件)? 没什么:爸爸!(策划者。活动)
end

功能 генерировать_запрос! 从设备创建一个新的网络请求:它增加请求计数器,生成一个唯一标识符,并立即安排一个事件,如 :запрос 对于当前时间,然后计算一个随机间隔(基于特征 интенсивность 设备)用于规划下一个事件 :генерация_запроса,从而模拟装置的周期性活动。

功能 обработать_запрос 接收数据传输请求并尝试为其分配路由器资源。 如果有空闲信道,则占用它,计算随机传输持续时间,并调度事件。 :конец_передачи 为未来,并显示成功消息。 如果所有通道都忙,该函数将请求ID放在路由器队列中,并显示一条关于备用状态的消息。

功能 завершить_передачу 数据传输完成后释放路由器通道,显示相应的消息。 然后它检查队列中的待处理请求:如果队列不为空,函数检索下一个请求,立即为其分配新释放的通道,安排其完成并输出消息,从而实现连续处理和先进先出原则(先进先出)。

In [ ]:
function_生成查询!(设备::设备,调度程序::事件调度程序, 
                              当前时间::Float64,router::路由器)
    装置。counter_query+=1
    запрос_ид = "$(设备。名称)-$((设备。counter_query,2,'0'))"
    
    event_query=事件(
        当前时间,
        :请求,
        device.name,
        (id=request_id,time_query=当前时间)
    )
    
    add_事件!(调度程序,event_query)
    
    下一次time_=当前time_+设备。强度*(0.5+兰特())
    下一个事件=事件(
        下一个时间,
        :generation_query,
        device.name,
        nothing
    )
    
    add_事件!(调度程序,下一个事件)
    
    println(" t=$(round(当前时间,数字=2))|$(device.name)/请求创建$request_id")
end

函数process_query(device::Device,Data,Scheduler::Event SchedulerefErences, 
                          路由器::路由器,当前时间::Float64)
    request_id=数据。标识符
    查询time_=data。time_query
    
    如果路由器。繁忙的通道<路由器。渠道
        的路由器。繁忙频道+=1
        
        传输时间_=0.5+rand()*2.0
        结束时间=当前时间+转移时间
        
        事件=事件(
            结束时间_,
            :end_transmission,
            device.name,
            (id=request_id,开始时间=当前时间, 
             transfer time_=转移时间_)
        )
        
        add_事件!(策划、活动)
        
        println(" t=$(round(当前时间,digits=2))|requ request_id|Channel received(等待:$(round(当前时间为请求的时间,digits=2)))")
    else
        推!(路由器。队列,request_id)
        println(" t=$(round(current time,digits=2))|requ request_id/Queued(length:$(length().队列)))")
    end
end

函数end_transmission(device::Device,Data,Scheduler::Event SchedulerefErences, 
                          路由器::路由器,当前时间::Float64)
    的路由器。繁忙频道-=1
    
    request_id=数据。标识符
    开始time_=数据。开始时间_
    time_transmission=数据。时间传递
    
    println("t=$(round(current time,digits=2))|requ request_id/Channel is released(transmission:$(round(transmission time_,digits=2)))")
    
    如果!isempty(路由器。队列)
        next_query=popfirst!(路由器。队列)
        имя_устройства = split(следующий_запрос, "-")[1]
        
        传输时间_=0.5+rand()*2.0
        结束时间=当前时间+转移时间
        
        事件=事件(
            结束时间_,
            :end_transmission,
            设备名称,
            (id=下一个查询,开始时间=当前时间,
             transfer time_=转移时间_)
        )
        
        add_事件!(策划、活动)
        
        的路由器。繁忙频道+=1
        println("t=$(round(current time,digits=2))|nex next_query/已从队列中移除并开始传输")
    end
end

功能 запустить_симуляцию 他是该计划的主要董事总经理。 它初始化所有系统组件:它创建一个事件调度器,一个具有设定数量的通道的路由器,以及具有随机特性的设定数量的客户端设备,之后它调度第一个请

然后该函数启动离散事件模拟的主循环,其连续地从调度器提取最早的事件,促进系统的虚拟时间并且,取决于事件的类型,将其重定向到处理三个关键: генерировать_запрос!, обработать_запросзавершить_передачу. 循环运行直到指定的模拟时间到期或直到事件用完,之后函数输出最终的网络统计信息并将其作为字典返回。

In [ ]:
function_simulation已启动(持续时间=30.0,设备数=4,路由器通道=2
    println("="^50)
    println("WI-FI网络模拟(纯JULIA)")
    println("="^50)
    println("参数:")
    println("  持续时间:▪单位时间持续时间")
    println("  设备:▪设备数量")
    println("  路由器通道:▪路由器通道")
    println("-"^50)
    
    scheduler=Event Planner()
    router=路由器(Router channels)
    
    device_dict=Dict{字符串,设备}()
    типы_устройств = ["一台笔记本电脑", "智能手机", "平板电脑", "电视"]
    
    对于i in1:设备数量
        类型=设备类型[mod1(i,长度(设备类型)]
        имя = "$(类型)_i i"
        强度=2.0+兰特()*3.0
        设备=设备(名称,强度,0)
        device_dict[name]=设备
        println("➕添加:$名称(间隔:$(round(intensity,digits=2)))")
        
        first_existence=事件(
            rand() * 1.0,
            :generation_query,
            姓名,
            nothing
        )
        add_事件!(规划师,first_event)
    end
    
    println("-"^50)
    println("运行模拟。..\n")
    
    统计=Dict{String,Int}()
    статистика["所有问题"] = 0
    статистика["转移/转移"] = 0
    
    而调度器。current_time<持续时间
        事件=下一个事件(调度程序)
        
        如果事件===没有
            break
        end
        
        计划者。current_time=事件。时间
        
        如果调度程序。当前时间>持续时间
            break
        end
        
        如果!haskey(device_dict,event.器)
            continue
        end
        
        设备=device_dict[事件。装置]
        
        如果事件。类型==:generation_query
            生成查询!(设备,调度器,调度器。当前时间,路由器)
            статистика["所有问题"] += 1
            
        elseif事件。类型==:请求
            process_query(设备,事件。数据,调度器,路由器,调度器。当前时间)
            
        elseif事件。类型==:end_transmission
            end_transmission(设备,事件。数据,调度器,路由器,调度器。当前时间)
            статистика["转移/转移"] += 1
        end
    end
    
    println("\n" * "-"^50)
    println("模拟统计")
    println("-"^50)
    println("总仿真时间:〇(round()。current_time,digits=2))")
    println("总请求:$(统计["всего_запросов"])")
    println("已完成的转帐:$(统计数字["передач_завершено"])")
    println("留在队列中:$(length(路由器。队列))")
    println("末端使用的通道数:$(路由器。忙频道)")
    println("="^50)
    
    返回统计数字
end
In [ ]:
run_simulation(25.0,5,2)
==================================================
WI-FI网络模拟(纯JULIA)
==================================================
参数:
  持续时间:25.0时间单位
  设备:5
  路由器通道:2
--------------------------------------------------
➕添加:Laptop_1(间隔:2.53)
,添加:Smartphone_2(间隔:4.12)
,添加:Planet_3(间隔:4.73)
,添加:TV_4(间隔:3.34)
,补充:笔记本5(间隔:4.24)
--------------------------------------------------
运行模拟。..

⏰t=0.03/Notebook_1/Notebook_1-01查询已创建
✅t=0.03/Laptop_1-01/通道接收(期望:0.0)
⏰t=0.1/Tablet_3/创建了Tablet_3-01请求
✅t=0.1|Tablet_3-01/通道接收(等待:0.0)
⏰t=0.14/笔记本5/请求笔记本5-01已创建
⌛t=0.14/笔记本5-01/排队(长度:1)
⏰t=0.36/Smartphone_2/请求Smartphone_2-01已创建
⌛t=0.36/Smartphone_2-01/排队(长度:2)
⏰t=0.42/TV_4/请求TV_4-01已创建
⌛t=0.42/TV_4-01/排队(长度:3)
🔓t=1.17/Tablet_3-01/频道发布(传输:1.07)
️️t=1.17/笔记本5-01/从队列中删除并开始传输
🔓t=2.32/Laptop_1-01/通道被释放(传输:2.3)
️️t=2.32/Smartphone_2-01/从队列中删除并开始传输
⏰t=2.68|Smartphone_2/Smartphone_2-02创建请求
⌛t=2.68/Smartphone_2-02/排队(长度:2)
⏰t=2.73|TV_4/请求创建TV_4-02
⌛t=2.73/TV_4-02/排队(长度:3)
🔓t=2.78/笔记本5-01/频道发布(传输:1.6)
️️t=2.78/TV_4-01/从队列中删除并开始传输
⏰t=2.79|Tablet_3/Tablet_3-02创建请求
⌛t=2.79/平板电脑3-02/排队(长度:3)
🔓t=3.29/TV_4-01/频道发布(传输:0.51)
️️t=3.29/Smartfect_2-02/已从队列中移除并开始传输
⏰t=3.67/Notebook_1/创建了Notebook_1-02请求
⌛t=3.67/笔记本1-02/排队(长度:3)
🔓t=4.79/Smartphone_2-01/信道发布(传输:2.46)
️️t=4.79/TV_4-02/从队列中删除并开始传输
🔓t=5.36/Smartphone_2-02/信道发布(传输:2.07)
️️t=5.36/平板电脑3-02/从队列中删除并开始传输
🔓t=5.71/TV_4-02/频道发布(传输:0.93)
️️t=5.71/笔记本1-02/从队列中删除并开始传输
⏰t=5.78/笔记本5/请求笔记本5-02已创建
⌛t=5.78/笔记本5-02/排队(长度:1)
⏰t=6.02|TV_4/请求创建TV_4-03
⌛t=6.02/TV_4-03/排队(长度:2)
🔓t=6.34/Notebook_1-02/频道发布(传输:0.62)
️️t=6.34/笔记本5-02/从队列中删除并开始传输
⏰t=6.73/Notebook_1/创建了Notebook_1-03请求
⌛t=6.73/笔记本1-03/排队(长度:2)
🔓t=7.41/平板电脑3-02/通道释放(传输:2.05)
️️t=7.41/TV_4-03/从队列中删除并开始传输
⏰t=7.81|TV_4/请求创建TV_4-04
⌛t=7.81/TV_4-04/排队(长度:2)
🔓t=8.0/笔记本5-02/频道发布(传输:1.67)
️️t=8.0/笔记本1-03/从队列中删除并开始传输
⏰t=8.34|Smartphone_2/Smartphone_2-03创建请求
⌛t=8.34/Smartphone_2-03/排队(长度:2)
⏰t=8.77/Laptop_1/请求Laptop_1-04已创建
⌛t=8.77/笔记本1-04/排队(长度:3)
⏰t=8.82|Tablet_3/Tablet_3-03创建请求
⌛t=8.82/平板电脑3-03/排队(长度:4)
🔓t=9.03/Notebook_1-03/通道被释放(传输:1.03)
️️t=9.03/TV_4-04/从队列中删除并开始传输
🔓t=9.18/TV_4-03/频道发布(传输:1.77)
️️t=9.18/Smartphone_2-03/从队列中删除并开始传输
⏰t=9.24/笔记本5/请求笔记本5-03已创建
⌛t=9.24/笔记本5-03/排队(长度:3)
🔓t=9.54/TV_4-04/频道发布(传输:0.51)
⚠️t=9.54/Notebook1-04/已从队列中移除并开始传输
⏰t=10.5|Smartphone_2/Smartphone_2-04创建请求
⌛t=10.5/Smartphone_2-04/排队(长度:3)
🔓t=10.93/笔记本1-04/频道发布(传输:1.39)
️️t=10.93/Tablet_3-03/从队列中删除并开始传输
🔓t=11.14/Smartphone_2-03/信道释放(传输:1.96)
️️t=11.14/笔记本5-03/从队列中删除并开始传输
⏰t=11.31|TV_4/请求创建TV_4-05
⌛t=11.31/TV_4-05/排队(长度:2)
🔓t=11.85/笔记本5-03/频道发布(传输:0.71)
️️t=11.85/Smartphone_2-04/从队列中删除并开始传输
⏰t=12.11/Notebook_1/创建了Notebook_1-05请求
⌛t=12.11/笔记本1-05/排队(长度:2)
🔓t=12.88/Tablet_3-03/频道发布(传输:1.95)
️️t=12.88/TV_4-05/从队列中删除并开始传输
🔓t=13.06/Smartphone_2-04/信道发布(传输:1.21)
️️t=13.06/笔记本1-05/从队列中删除并开始传输
🔓t=13.46/TV_4-05/频道发布(传输:0.57)
⏰t=13.68|Tablet_3/Tablet_3-04创建请求
✅t=13.68|Tablet_3-04/信道接收(期望:0.0)
🔓t=13.86/笔记本1-05/频道发布(传输:0.8)
⏰t=14.62/笔记本5/请求笔记本5-04已创建
✅t=14.62/笔记本5-04/频道接收(等待:0.0)
🔓t=14.69/平板电脑3-04|频道发布(传输:1.01)
⏰t=15.36|TV_4/请求创建TV_4-06
✅t=15.36/TV_4-06/频道接收(期望:0.0)
⏰t=15.66/Notebook_1/请求Notebook_1-06已创建
⌛t=15.66/笔记本1-06/排队(长度:1)
⏰t=15.99/Smartphone_2/智能手机请求Created_2-05
⌛t=15.99/Smartphone_2-05/排队(长度:2)
🔓t=16.43/TV_4-06/频道发布(传输:1.07)
️️t=16.43/笔记本1-06/从队列中删除并开始传输
🔓t=16.48/笔记本5-04/频道发布(传输:1.86)
️️t=16.48/Smartfect_2-05/已从队列中移除并开始传输
🔓t=17.32/笔记本1-06/频道发布(传输:0.89)
⏰t=17.43|Tablet_3/Tablet_3-05创建请求
✅t=17.43|Tablet_3-05/信道接收(期望:0.0)
⏰t=17.57/Notebook_1/请求Notebook_1-07已创建
⌛t=17.57/笔记本1-07/排队(长度:1)
🔓t=18.84/Smartphone_2-05/信道释放(传输:2.36)
⚠️t=18.84/Notebook1-07/已从队列中移除并开始传输
🔓t=19.02/Tablet_3-05/频道发布(传输:1.59)
⏰t=19.06/笔记本5/请求笔记本5-05已创建
✅t=19.06/笔记本5-05/频道收到(等待:0.0)
⏰t=20.06/TV_4/创建了TV_4-07的请求
⌛t=20.06/TV_4-07/排队(长度:1)
⏰t=20.28|Smartphone_2/Smartphone_2-06创建请求
⌛t=20.28/Smartphone_2-06/排队(长度:2)
🔓t=20.29/笔记本5-05/频道发布(传输:1.23)
️️t=20.29/TV_4-07/从队列中删除并开始传输
⏰t=20.38/Notebook_1/请求Notebook_1-08已创建
⌛t=20.38/笔记本1-08/排队(长度:2)
🔓t=20.88/Laptop_1-07/通道被释放(传输:2.04)
️️t=20.88/Smartphone_2-06/已从队列中移除并开始传输
⏰t=21.66|Tablet_3/Tablet_3-06创建请求
⌛t=21.66/平板电脑3-06/排队(长度:2)
🔓t=21.85/TV_4-07/频道发布(传输:1.55)
⚠️t=21.85/Notebook1-08/已从队列中移除并开始传输
⏰t=22.03/笔记本5/创建了一个请求笔记本5-06
⌛t=22.03/笔记本5-06/排队(长度:2)
⏰t=22.45/Notebook_1/请求Notebook_1-09已创建
⌛t=22.45/笔记本1-09/排队(长度:3)
⏰t=22.6|TV_4/请求创建TV_4-08
⌛t=22.6/TV_4-08/排队(长度:4)
🔓t=22.74/Smartphone_2-06/信道释放(传输:1.86)
️️t=22.74/平板电脑3-06/从队列中删除并开始传输
🔓t=23.3/平板电脑3-06|频道发布(传输:0.56)
⚠️t=23.3/Notebook5-06/已从队列中移除并开始传输
🔓t=23.72/笔记本1-08/频道发布(传输:1.88)
️️t=23.72/笔记本1-09/从队列中删除并开始传输
⏰t=24.47/TV_4/为TV_4-09创建了请求
⌛t=24.47/TV_4-09/排队(长度:2)
🔓t=24.52/笔记本5-06/频道发布(传输:1.22)
️️t=24.52/TV_4-08/从队列中删除并开始传输
⏰t=24.52|Smartphone_2/Smartphone_2-07创建请求
⌛t=24.52/Smartphone_2-07/排队(长度:2)

--------------------------------------------------
模拟统计
--------------------------------------------------
总模拟时间:25.48
总请求:37
已完成的转帐:33
留在队列中:2
结束时占用的信道:2
==================================================
Out[0]:
Dict{String, Int64} with 2 entries:
  "转移/转移" => 33
  "所有问题"    => 37

仿真演示了网络在周期性过载状态下的运行:有五个活动设备和只有两个路由器通道,系统中不断形成一个等待队列,其峰值长度可以达到几个请求,这表明当前负载系统性地缺乏带宽。 操作时间有一个明确的划分阶段:在初始阶段,当队列尚未形成时,请求几乎立即得到服务,但随着负载的积累,大多数设备被迫花费相当长的时间等待空闲信道,其中一些设备产生强度更高的请求,产生了不成比例的大负载,增加了平均等待时间。 对于网络的所有成员。 虽然整个系统处理绝大多数请求,但在会话结束时出现队列和所有通道的不断使用表明它正在发挥其能力的极限,在这种情况下,请求强度或设备数量的任何增加都将导致延迟的急剧增加和总体效率的下降。

结论

此实现演示了如何在没有外部依赖的情况下在纯Julia上构建功能齐全的离散事件模型。 此代码为试验网络算法提供了良好的基础。 您可以轻松修改它以探索不同的场景:添加不同的服务类,设备优先级,丢包模型或实时可视化。

这种实现的主要优点是完全控制仿真逻辑和不存在依赖关系,这使得代码成为训练和原型网络模型的理想选择。