Engee documentation
Notebook

Discrete event model of a Wi-Fi network

The model simulates the operation of a router with a limited number of parallel channels and several client devices that generate network traffic. The simulator demonstrates the fundamental principles of wireless networks, including competition for resources, queuing, and channel loading dynamics
.\ The main elements of our model are described below. Structure Событие It is a fundamental element of the discrete event model and represents a separate occurrence in the system that occurs at a specific time. It stores four main attributes. Field время It contains a timestamp indicating when an event should occur in conditional simulation units, which allows the scheduler to arrange events in chronological order. Field тип defines the event category using a Symbol, such as :генерация_запроса, :запрос or :конец_передачи, which dictates which processing function should be called. Field устройство binds an event to its source or recipient by storing the string identifier of a specific client device (for example, "Laptop_1"). Finally, the field данные It is intended for storing any additional information related to an event, in the form of a tuple of named fields or another type; for example, for a request event, a unique request identifier and the time of its creation can be stored here. This structure is immutable, which guarantees the integrity of the event data after its creation throughout the simulation.

Structure Устройство simulates client hardware on a Wi-Fi network, such as a laptop or smartphone. It is mutable, since its state must be updated during the simulation. The structure includes three fields. Field имя It contains a unique string identifier of the device, for example "Smartphone_2", which is used to associate events and requests with their source. Field интенсивность determines the behavior of the device by storing the average time (in conditional simulation units) between the generation of consecutive data requests; the lower this number, the more often the device creates a load on the network. Field счетчик_запросов It tracks the total number of requests generated by this device since the beginning of the simulation; this value is incremented with each new request and is often used to generate unique identifiers for these requests.

Structure Роутер represents a Wi-Fi hotspot model with limited resources. This is a changeable structure, as the status of channels and queues is constantly changing. It includes three fields. Field каналы defines the maximum bandwidth of the router by storing an integer that indicates the number of parallel connections or channels available for simultaneous data transmission (for example, 2). The field занятые_каналы It tracks the current load, showing how many of the available channels are currently busy processing data transmission. Field очередь it is a vector of strings (Vector{String}), where each string is the identifier of a request (for example, "Laptop_1-03") from a device that tried to start transmitting, but all channels were busy; this vector implements FIFO (First—In, First-Out) logic, where the first The first incoming request will be served in the queue. The structure has a constructor Роутер(каналы::Int) which, when creating a new object, automatically initializes the number of occupied channels to zero and creates an empty queue, ensuring the correct initial state of the model.

Structure ПланировщикСобытий it is the core of the discrete event simulation engine, responsible for managing the time and sequence of all operations. This is a mutable structure. It contains two fields. Field события It is a chronologically ordered collection of all scheduled but not yet processed events, stored as a vector of structures. Событие. To efficiently extract the next event in time, the vector is maintained in a time-sorted state, which allows you to quickly extract the earliest event from the end of the vector. Field текущее_время stores the virtual time point to which the simulation has progressed; this value is updated each time a new event is retrieved and processed, and serves as a global clock for the entire model. The structure has a constructor ПланировщикСобытий(), which initializes an empty list of events and sets the initial simulation time to 0.0. The main simulation loop constantly requests the scheduler for the next event, updates текущее_время at the time of this event, and transmits the event for processing to the appropriate functions, thereby simulating the passage of time in the system.

In [ ]:
struct Событие
    время::Float64
    тип::Symbol
    устройство::String
    данные::Any
end

mutable struct Устройство
    имя::String
    интенсивность::Float64
    счетчик_запросов::Int
end

mutable struct Роутер
    каналы::Int
    занятые_каналы::Int
    очередь::Vector{String}
    
    function Роутер(каналы::Int)
        new(каналы, 0, String[])
    end
end

mutable struct ПланировщикСобытий
    события::Vector{Событие}
    текущее_время::Float64
    
    function ПланировщикСобытий()
        new(Событие[], 0.0)
    end
end

Function добавить_событие! places a new event in the scheduler and sorts the entire list by time in reverse order, ensuring that the earliest event is always at the end of the vector. Function следующее_событие retrieves and returns this earliest event from the end of the vector, and if the list is empty, returns nothing, which signals the end of the simulation.

In [ ]:
function добавить_событие!(планировщик::ПланировщикСобытий, событие::Событие)
    push!(планировщик.события, событие)
    sort!(планировщик.события, by=x->x.время, rev=true)
end

function следующее_событие(планировщик::ПланировщикСобытий)
    isempty(планировщик.события) ? nothing : pop!(планировщик.события)
end

Function генерировать_запрос! creates a new network request from the device: it increments the request counter, generates a unique identifier, and immediately schedules an event like :запрос for the current time, and then calculates a random interval (based on the characteristic интенсивность devices) for planning the next event :генерация_запроса, thereby simulating the periodic activity of the device.

Function обработать_запрос receives a data transfer request and tries to allocate a router resource for it. If there is a free channel, it occupies it, calculates a random transmission duration, and schedules an event. :конец_передачи for the future, and displays a success message. If all channels are busy, the function places the request ID in the router queue and displays a message about the standby status.

Function завершить_передачу releases the router channel after the data transfer is completed, displaying the corresponding message. Then it checks for pending requests in the queue: if the queue is not empty, the function retrieves the next request, immediately allocates the newly released channel for it, schedules its completion and outputs a message, thus implementing continuous processing and the FIFO principle (First-In, First-Out).

In [ ]:
function генерировать_запрос!(устройство::Устройство, планировщик::ПланировщикСобытий, 
                              текущее_время::Float64, роутер::Роутер)
    устройство.счетчик_запросов += 1
    запрос_ид = "$(устройство.имя)-$(lpad(устройство.счетчик_запросов, 2, '0'))"
    
    событие_запрос = Событие(
        текущее_время,
        :запрос,
        устройство.имя,
        (идентификатор=запрос_ид, время_запроса=текущее_время)
    )
    
    добавить_событие!(планировщик, событие_запрос)
    
    следующее_время = текущее_время + устройство.интенсивность * (0.5 + rand())
    следующее_событие = Событие(
        следующее_время,
        :генерация_запроса,
        устройство.имя,
        nothing
    )
    
    добавить_событие!(планировщик, следующее_событие)
    
    println("⏰ t=$(round(текущее_время, digits=2)) | $(устройство.имя) | Создан запрос $запрос_ид")
end

function обработать_запрос(устройство::Устройство, данные, планировщик::ПланировщикСобытий, 
                          роутер::Роутер, текущее_время::Float64)
    запрос_ид = данные.идентификатор
    время_запроса = данные.время_запроса
    
    if роутер.занятые_каналы < роутер.каналы
        роутер.занятые_каналы += 1
        
        время_передачи = 0.5 + rand() * 2.0
        время_окончания = текущее_время + время_передачи
        
        событие = Событие(
            время_окончания,
            :конец_передачи,
            устройство.имя,
            (идентификатор=запрос_ид, время_начала=текущее_время, 
             время_передачи=время_передачи)
        )
        
        добавить_событие!(планировщик, событие)
        
        println("✅ t=$(round(текущее_время, digits=2)) | $запрос_ид | Канал получен (ожидание: $(round(текущее_время-время_запроса, digits=2)))")
    else
        push!(роутер.очередь, запрос_ид)
        println("⌛ t=$(round(текущее_время, digits=2)) | $запрос_ид | Поставлен в очередь (длина: $(length(роутер.очередь)))")
    end
end

function завершить_передачу(устройство::Устройство, данные, планировщик::ПланировщикСобытий, 
                          роутер::Роутер, текущее_время::Float64)
    роутер.занятые_каналы -= 1
    
    запрос_ид = данные.идентификатор
    время_начала = данные.время_начала
    время_передачи = данные.время_передачи
    
    println("🔓 t=$(round(текущее_время, digits=2)) | $запрос_ид | Канал освобожден (передача: $(round(время_передачи, digits=2)))")
    
    if !isempty(роутер.очередь)
        следующий_запрос = popfirst!(роутер.очередь)
        имя_устройства = split(следующий_запрос, "-")[1]
        
        время_передачи = 0.5 + rand() * 2.0
        время_окончания = текущее_время + время_передачи
        
        событие = Событие(
            время_окончания,
            :конец_передачи,
            имя_устройства,
            (идентификатор=следующий_запрос, время_начала=текущее_время,
             время_передачи=время_передачи)
        )
        
        добавить_событие!(планировщик, событие)
        
        роутер.занятые_каналы += 1
        println("➡️  t=$(round(текущее_время, digits=2)) | $следующий_запрос | Извлечен из очереди и начал передачу")
    end
end

Function запустить_симуляцию He is the main managing director of the program. It initializes all system components: it creates an event scheduler, a router with a set number of channels, and a set number of client devices with random characteristics, after which it schedules the first request generation event for each of them.

Then the function starts the main cycle of discrete event simulation, which continuously extracts the earliest event from the scheduler, advances the virtual time of the system and, depending on the type of event, redirects it to processing one of the three key functions.: генерировать_запрос!, обработать_запрос or завершить_передачу. The loop runs until the specified simulation time expires or until the events run out, after which the function outputs the final network statistics and returns them as a dictionary.

In [ ]:
function запустить_симуляцию(длительность=30.0, количество_устройств=4, каналы_роутера=2)
    println("="^50)
    println("WI-FI NETWORK SIMULATION (PURE JULIA)")
    println("="^50)
    println("Parameters:")
    println("  Длительность: $длительность ед. времени")
    println("  Устройства: $количество_устройств")
    println("  Каналы роутера: $каналы_роутера")
    println("-"^50)
    
    планировщик = ПланировщикСобытий()
    роутер = Роутер(каналы_роутера)
    
    устройства_dict = Dict{String, Устройство}()
    типы_устройств = ["Ноутбук", "Смартфон", "Планшет", "ТВ"]
    
    for i in 1:количество_устройств
        тип = типы_устройств[mod1(i, length(типы_устройств))]
        имя = "$(тип)_$i"
        интенсивность = 2.0 + rand() * 3.0
        устройство = Устройство(имя, интенсивность, 0)
        устройства_dict[имя] = устройство
        println("➕ Добавлено: $имя (интервал: $(round(интенсивность, digits=2)))")
        
        первое_событие = Событие(
            rand() * 1.0,
            :генерация_запроса,
            имя,
            nothing
        )
        добавить_событие!(планировщик, первое_событие)
    end
    
    println("-"^50)
    println("Запуск симуляции...\n")
    
    статистика = Dict{String, Int}()
    статистика["всего_запросов"] = 0
    статистика["передач_завершено"] = 0
    
    while планировщик.текущее_время < длительность
        событие = следующее_событие(планировщик)
        
        if событие === nothing
            break
        end
        
        планировщик.текущее_время = событие.время
        
        if планировщик.текущее_время > длительность
            break
        end
        
        if !haskey(устройства_dict, событие.устройство)
            continue
        end
        
        устройство = устройства_dict[событие.устройство]
        
        if событие.тип == :генерация_запроса
            генерировать_запрос!(устройство, планировщик, планировщик.текущее_время, роутер)
            статистика["всего_запросов"] += 1
            
        elseif событие.тип == :запрос
            обработать_запрос(устройство, событие.данные, планировщик, роутер, планировщик.текущее_время)
            
        elseif событие.тип == :конец_передачи
            завершить_передачу(устройство, событие.данные, планировщик, роутер, планировщик.текущее_время)
            статистика["передач_завершено"] += 1
        end
    end
    
    println("\n" * "-"^50)
    println("SIMULATION STATISTICS")
    println("-"^50)
    println("Общее время симуляции: $(round(планировщик.текущее_время, digits=2))")
    println("Всего запросов: $(статистика["всего_запросов"])")
    println("Передач завершено: $(статистика["передач_завершено"])")
    println("Осталось в очереди: $(length(роутер.очередь))")
    println("Занято каналов в конце: $(роутер.занятые_каналы)")
    println("="^50)
    
    return статистика
end
In [ ]:
запустить_симуляцию(25.0, 5, 2)
==================================================
СИМУЛЯЦИЯ WI-FI СЕТИ (ЧИСТЫЙ JULIA)
==================================================
Параметры:
  Длительность: 25.0 ед. времени
  Устройства: 5
  Каналы роутера: 2
--------------------------------------------------
➕ Добавлено: Ноутбук_1 (интервал: 2.53)
➕ Добавлено: Смартфон_2 (интервал: 4.12)
➕ Добавлено: Планшет_3 (интервал: 4.73)
➕ Добавлено: ТВ_4 (интервал: 3.34)
➕ Добавлено: Ноутбук_5 (интервал: 4.24)
--------------------------------------------------
Запуск симуляции...

⏰ t=0.03 | Ноутбук_1 | Создан запрос Ноутбук_1-01
✅ t=0.03 | Ноутбук_1-01 | Канал получен (ожидание: 0.0)
⏰ t=0.1 | Планшет_3 | Создан запрос Планшет_3-01
✅ t=0.1 | Планшет_3-01 | Канал получен (ожидание: 0.0)
⏰ t=0.14 | Ноутбук_5 | Создан запрос Ноутбук_5-01
⌛ t=0.14 | Ноутбук_5-01 | Поставлен в очередь (длина: 1)
⏰ t=0.36 | Смартфон_2 | Создан запрос Смартфон_2-01
⌛ t=0.36 | Смартфон_2-01 | Поставлен в очередь (длина: 2)
⏰ t=0.42 | ТВ_4 | Создан запрос ТВ_4-01
⌛ t=0.42 | ТВ_4-01 | Поставлен в очередь (длина: 3)
🔓 t=1.17 | Планшет_3-01 | Канал освобожден (передача: 1.07)
➡️  t=1.17 | Ноутбук_5-01 | Извлечен из очереди и начал передачу
🔓 t=2.32 | Ноутбук_1-01 | Канал освобожден (передача: 2.3)
➡️  t=2.32 | Смартфон_2-01 | Извлечен из очереди и начал передачу
⏰ t=2.68 | Смартфон_2 | Создан запрос Смартфон_2-02
⌛ t=2.68 | Смартфон_2-02 | Поставлен в очередь (длина: 2)
⏰ t=2.73 | ТВ_4 | Создан запрос ТВ_4-02
⌛ t=2.73 | ТВ_4-02 | Поставлен в очередь (длина: 3)
🔓 t=2.78 | Ноутбук_5-01 | Канал освобожден (передача: 1.6)
➡️  t=2.78 | ТВ_4-01 | Извлечен из очереди и начал передачу
⏰ t=2.79 | Планшет_3 | Создан запрос Планшет_3-02
⌛ t=2.79 | Планшет_3-02 | Поставлен в очередь (длина: 3)
🔓 t=3.29 | ТВ_4-01 | Канал освобожден (передача: 0.51)
➡️  t=3.29 | Смартфон_2-02 | Извлечен из очереди и начал передачу
⏰ t=3.67 | Ноутбук_1 | Создан запрос Ноутбук_1-02
⌛ t=3.67 | Ноутбук_1-02 | Поставлен в очередь (длина: 3)
🔓 t=4.79 | Смартфон_2-01 | Канал освобожден (передача: 2.46)
➡️  t=4.79 | ТВ_4-02 | Извлечен из очереди и начал передачу
🔓 t=5.36 | Смартфон_2-02 | Канал освобожден (передача: 2.07)
➡️  t=5.36 | Планшет_3-02 | Извлечен из очереди и начал передачу
🔓 t=5.71 | ТВ_4-02 | Канал освобожден (передача: 0.93)
➡️  t=5.71 | Ноутбук_1-02 | Извлечен из очереди и начал передачу
⏰ t=5.78 | Ноутбук_5 | Создан запрос Ноутбук_5-02
⌛ t=5.78 | Ноутбук_5-02 | Поставлен в очередь (длина: 1)
⏰ t=6.02 | ТВ_4 | Создан запрос ТВ_4-03
⌛ t=6.02 | ТВ_4-03 | Поставлен в очередь (длина: 2)
🔓 t=6.34 | Ноутбук_1-02 | Канал освобожден (передача: 0.62)
➡️  t=6.34 | Ноутбук_5-02 | Извлечен из очереди и начал передачу
⏰ t=6.73 | Ноутбук_1 | Создан запрос Ноутбук_1-03
⌛ t=6.73 | Ноутбук_1-03 | Поставлен в очередь (длина: 2)
🔓 t=7.41 | Планшет_3-02 | Канал освобожден (передача: 2.05)
➡️  t=7.41 | ТВ_4-03 | Извлечен из очереди и начал передачу
⏰ t=7.81 | ТВ_4 | Создан запрос ТВ_4-04
⌛ t=7.81 | ТВ_4-04 | Поставлен в очередь (длина: 2)
🔓 t=8.0 | Ноутбук_5-02 | Канал освобожден (передача: 1.67)
➡️  t=8.0 | Ноутбук_1-03 | Извлечен из очереди и начал передачу
⏰ t=8.34 | Смартфон_2 | Создан запрос Смартфон_2-03
⌛ t=8.34 | Смартфон_2-03 | Поставлен в очередь (длина: 2)
⏰ t=8.77 | Ноутбук_1 | Создан запрос Ноутбук_1-04
⌛ t=8.77 | Ноутбук_1-04 | Поставлен в очередь (длина: 3)
⏰ t=8.82 | Планшет_3 | Создан запрос Планшет_3-03
⌛ t=8.82 | Планшет_3-03 | Поставлен в очередь (длина: 4)
🔓 t=9.03 | Ноутбук_1-03 | Канал освобожден (передача: 1.03)
➡️  t=9.03 | ТВ_4-04 | Извлечен из очереди и начал передачу
🔓 t=9.18 | ТВ_4-03 | Канал освобожден (передача: 1.77)
➡️  t=9.18 | Смартфон_2-03 | Извлечен из очереди и начал передачу
⏰ t=9.24 | Ноутбук_5 | Создан запрос Ноутбук_5-03
⌛ t=9.24 | Ноутбук_5-03 | Поставлен в очередь (длина: 3)
🔓 t=9.54 | ТВ_4-04 | Канал освобожден (передача: 0.51)
➡️  t=9.54 | Ноутбук_1-04 | Извлечен из очереди и начал передачу
⏰ t=10.5 | Смартфон_2 | Создан запрос Смартфон_2-04
⌛ t=10.5 | Смартфон_2-04 | Поставлен в очередь (длина: 3)
🔓 t=10.93 | Ноутбук_1-04 | Канал освобожден (передача: 1.39)
➡️  t=10.93 | Планшет_3-03 | Извлечен из очереди и начал передачу
🔓 t=11.14 | Смартфон_2-03 | Канал освобожден (передача: 1.96)
➡️  t=11.14 | Ноутбук_5-03 | Извлечен из очереди и начал передачу
⏰ t=11.31 | ТВ_4 | Создан запрос ТВ_4-05
⌛ t=11.31 | ТВ_4-05 | Поставлен в очередь (длина: 2)
🔓 t=11.85 | Ноутбук_5-03 | Канал освобожден (передача: 0.71)
➡️  t=11.85 | Смартфон_2-04 | Извлечен из очереди и начал передачу
⏰ t=12.11 | Ноутбук_1 | Создан запрос Ноутбук_1-05
⌛ t=12.11 | Ноутбук_1-05 | Поставлен в очередь (длина: 2)
🔓 t=12.88 | Планшет_3-03 | Канал освобожден (передача: 1.95)
➡️  t=12.88 | ТВ_4-05 | Извлечен из очереди и начал передачу
🔓 t=13.06 | Смартфон_2-04 | Канал освобожден (передача: 1.21)
➡️  t=13.06 | Ноутбук_1-05 | Извлечен из очереди и начал передачу
🔓 t=13.46 | ТВ_4-05 | Канал освобожден (передача: 0.57)
⏰ t=13.68 | Планшет_3 | Создан запрос Планшет_3-04
✅ t=13.68 | Планшет_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 | ТВ_4 | Создан запрос ТВ_4-06
✅ t=15.36 | ТВ_4-06 | Канал получен (ожидание: 0.0)
⏰ t=15.66 | Ноутбук_1 | Создан запрос Ноутбук_1-06
⌛ t=15.66 | Ноутбук_1-06 | Поставлен в очередь (длина: 1)
⏰ t=15.99 | Смартфон_2 | Создан запрос Смартфон_2-05
⌛ t=15.99 | Смартфон_2-05 | Поставлен в очередь (длина: 2)
🔓 t=16.43 | ТВ_4-06 | Канал освобожден (передача: 1.07)
➡️  t=16.43 | Ноутбук_1-06 | Извлечен из очереди и начал передачу
🔓 t=16.48 | Ноутбук_5-04 | Канал освобожден (передача: 1.86)
➡️  t=16.48 | Смартфон_2-05 | Извлечен из очереди и начал передачу
🔓 t=17.32 | Ноутбук_1-06 | Канал освобожден (передача: 0.89)
⏰ t=17.43 | Планшет_3 | Создан запрос Планшет_3-05
✅ t=17.43 | Планшет_3-05 | Канал получен (ожидание: 0.0)
⏰ t=17.57 | Ноутбук_1 | Создан запрос Ноутбук_1-07
⌛ t=17.57 | Ноутбук_1-07 | Поставлен в очередь (длина: 1)
🔓 t=18.84 | Смартфон_2-05 | Канал освобожден (передача: 2.36)
➡️  t=18.84 | Ноутбук_1-07 | Извлечен из очереди и начал передачу
🔓 t=19.02 | Планшет_3-05 | Канал освобожден (передача: 1.59)
⏰ t=19.06 | Ноутбук_5 | Создан запрос Ноутбук_5-05
✅ t=19.06 | Ноутбук_5-05 | Канал получен (ожидание: 0.0)
⏰ t=20.06 | ТВ_4 | Создан запрос ТВ_4-07
⌛ t=20.06 | ТВ_4-07 | Поставлен в очередь (длина: 1)
⏰ t=20.28 | Смартфон_2 | Создан запрос Смартфон_2-06
⌛ t=20.28 | Смартфон_2-06 | Поставлен в очередь (длина: 2)
🔓 t=20.29 | Ноутбук_5-05 | Канал освобожден (передача: 1.23)
➡️  t=20.29 | ТВ_4-07 | Извлечен из очереди и начал передачу
⏰ t=20.38 | Ноутбук_1 | Создан запрос Ноутбук_1-08
⌛ t=20.38 | Ноутбук_1-08 | Поставлен в очередь (длина: 2)
🔓 t=20.88 | Ноутбук_1-07 | Канал освобожден (передача: 2.04)
➡️  t=20.88 | Смартфон_2-06 | Извлечен из очереди и начал передачу
⏰ t=21.66 | Планшет_3 | Создан запрос Планшет_3-06
⌛ t=21.66 | Планшет_3-06 | Поставлен в очередь (длина: 2)
🔓 t=21.85 | ТВ_4-07 | Канал освобожден (передача: 1.55)
➡️  t=21.85 | Ноутбук_1-08 | Извлечен из очереди и начал передачу
⏰ t=22.03 | Ноутбук_5 | Создан запрос Ноутбук_5-06
⌛ t=22.03 | Ноутбук_5-06 | Поставлен в очередь (длина: 2)
⏰ t=22.45 | Ноутбук_1 | Создан запрос Ноутбук_1-09
⌛ t=22.45 | Ноутбук_1-09 | Поставлен в очередь (длина: 3)
⏰ t=22.6 | ТВ_4 | Создан запрос ТВ_4-08
⌛ t=22.6 | ТВ_4-08 | Поставлен в очередь (длина: 4)
🔓 t=22.74 | Смартфон_2-06 | Канал освобожден (передача: 1.86)
➡️  t=22.74 | Планшет_3-06 | Извлечен из очереди и начал передачу
🔓 t=23.3 | Планшет_3-06 | Канал освобожден (передача: 0.56)
➡️  t=23.3 | Ноутбук_5-06 | Извлечен из очереди и начал передачу
🔓 t=23.72 | Ноутбук_1-08 | Канал освобожден (передача: 1.88)
➡️  t=23.72 | Ноутбук_1-09 | Извлечен из очереди и начал передачу
⏰ t=24.47 | ТВ_4 | Создан запрос ТВ_4-09
⌛ t=24.47 | ТВ_4-09 | Поставлен в очередь (длина: 2)
🔓 t=24.52 | Ноутбук_5-06 | Канал освобожден (передача: 1.22)
➡️  t=24.52 | ТВ_4-08 | Извлечен из очереди и начал передачу
⏰ t=24.52 | Смартфон_2 | Создан запрос Смартфон_2-07
⌛ t=24.52 | Смартфон_2-07 | Поставлен в очередь (длина: 2)

--------------------------------------------------
СТАТИСТИКА СИМУЛЯЦИИ
--------------------------------------------------
Общее время симуляции: 25.48
Всего запросов: 37
Передач завершено: 33
Осталось в очереди: 2
Занято каналов в конце: 2
==================================================
Out[0]:
Dict{String, Int64} with 2 entries:
  "передач_завершено" => 33
  "всего_запросов"    => 37

The simulation demonstrates the operation of the network in a state of periodic overload: with five active devices and only two router channels, a waiting queue is constantly formed in the system, the peak length of which can reach several requests, which indicates a systematic lack of bandwidth for the current load. There is a clear division of operating time into phases: in the initial period, when the queue has not yet been formed, requests are served almost instantly, but as the load accumulates, most devices are forced to spend considerable time waiting for a free channel, and some of them, generating requests with higher intensity, create a disproportionately large load, increasing the average waiting time. for all members of the network. Although the system as a whole copes with processing the vast majority of requests, the presence of a queue by the end of the session and the constant employment of all channels indicate that it is working at the limit of its capabilities, where any increase in the intensity of requests or the number of devices will lead to a sharp increase in delays and a decrease in overall efficiency.

Conclusion

This implementation demonstrates how a fully functional discrete event model can be built on pure Julia without external dependencies. This code provides an excellent basis for experimenting with network algorithms. You can easily modify it to explore different scenarios: add different service classes, device priorities, packet loss models, or real-time visualization.

The main advantage of this implementation is full control over the simulation logic and the absence of dependencies, which makes the code ideal for training and prototyping network models.