You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

M/M/K队列R模拟平均队长与理论值不符,求排查修正

M/M/1队列模拟结果与理论值不符的问题分析与修正

问题背景

使用R语言模拟M/M/1队列系统:到达率λ=8,服务率μ=10,服务器数量为1。根据M/M/1队列的稳态理论公式,平均队长应为ρ/(1-ρ)(其中ρ=λ/μ=0.8),计算得理论值为4。但模拟后计算所有时间点的队列长度均值为2.46215,与理论值差距较大。

用户的模拟代码如下:

1. 参数定义

set.seed(123)
library(ggplot2)
library(tidyr)
library(dplyr)
library(gridExtra)

#  simulation parameters
lambda <- 8          # Arrival rate
mu <- 10               # Service rate
sim_time <- 200       # Simulation time
k_minutes <- 15       # Threshold for waiting time
num_simulations <- 100  # Number of simulations to run
initial_queue_size <- 0  # Initial queue size
time_step <- 1        # Time step for discretization

servers <- c(1)  

2. 单次模拟函数

# single simulation
run_simulation <- function(num_servers) {
    queue <- initial_queue_size
    processed <- 0
    waiting_times <- numeric(0)
    queue_length <- numeric(sim_time)
    processed_over_time <- numeric(sim_time)
    long_wait_percent <- numeric(sim_time)
    
    for (t in 1:sim_time) {
        # Process arrivals
        arrivals <- rpois(1, lambda * time_step)
        queue <- queue + arrivals
        
        # Process departures
        departures <- min(queue, rpois(1, num_servers * mu * time_step))
        queue <- queue - departures
        processed <- processed + departures
        
        # Update waiting times
        if (length(waiting_times) > 0) {
            waiting_times <- waiting_times + time_step
        }
        if (arrivals > 0) {
            waiting_times <- c(waiting_times, rep(0, arrivals))
        }
        if (departures > 0) {
            waiting_times <- waiting_times[-(1:departures)]
        }
        
        # Record metrics
        queue_length[t] <- queue
        processed_over_time[t] <- processed
        long_wait_percent[t] <- ifelse(length(waiting_times) > 0,
                                       sum(waiting_times > k_minutes) / length(waiting_times) * 100,
                                       0)
    }
    
    return(list(queue_length = queue_length, 
                processed_over_time = processed_over_time, 
                long_wait_percent = long_wait_percent))
}

3. 执行模拟与数据整理

results <- lapply(servers, function(s) {
    replicate(num_simulations, run_simulation(s), simplify = FALSE)
})

# Function to create data frames for plotting
create_plot_data <- function(results, num_servers) {
    plot_data_queue <- data.frame(
        Time = rep(1:sim_time, num_simulations),
        QueueLength = unlist(lapply(results, function(x) x$queue_length)),
        Simulation = rep(1:num_simulations, each = sim_time),
        Servers = num_servers
    )
    
    plot_data_processed <- data.frame(
        Time = rep(1:sim_time, num_simulations),
        ProcessedOrders = unlist(lapply(results, function(x) x$processed_over_time)),
        Simulation = rep(1:num_simulations, each = sim_time),
        Servers = num_servers
    )
    
    plot_data_wait <- data.frame(
        Time = rep(1:sim_time, num_simulations),
        LongWaitPercent = unlist(lapply(results, function(x) x$long_wait_percent)),
        Simulation = rep(1:num_simulations, each = sim_time),
        Servers = num_servers
    )
    
    return(list(queue = plot_data_queue, processed = plot_data_processed, wait = plot_data_wait))
}

plot_data <- lapply(seq_along(servers), function(i) {
    create_plot_data(results[[i]], servers[i])
})

plot_data_queue <- do.call(rbind, lapply(plot_data, function(x) x$queue))
plot_data_processed <- do.call(rbind, lapply(plot_data, function(x) x$processed))
plot_data_wait <- do.call(rbind, lapply(plot_data, function(x) x$wait))

模拟后计算平均队长:

> mean(plot_data_queue$QueueLength)
[1] 2.46215

问题分析

1. 未排除暂态阶段

M/M队列从空队列(初始队列长度0)开始模拟,前一段时间系统处于暂态阶段,队列长度还未收敛到稳态值。直接对所有时间点(包括暂态)取均值,会拉低整体结果,因为暂态期的队列长度普遍远低于稳态值。

2. 离散时间步的近似误差

当前模拟采用离散时间步(time_step=1),用泊松分布近似到达和离开事件。虽然泊松分布的期望符合速率要求,但离散时间的近似会引入误差,尤其是当时间步长较大时,无法精确模拟连续时间下的指数分布间隔。

3. 离开事件模拟的逻辑瑕疵

对于单服务器,当队列中有顾客时,服务器持续处于忙碌状态,服务完成的事件是指数分布。当前用rpois(1, num_servers * mu * time_step)生成离开数,虽然期望正确,但在离散时间步下,可能出现单次时间步内离开多个顾客的情况(单服务器在1个时间步内完成多个服务),这不符合M/M/1队列的单服务台逻辑(一个服务器同一时间只能处理一个顾客)。


修正方案

方案1:排除暂态期,延长模拟时间

修改点:

  • 延长模拟时间至1000,给系统足够时间进入稳态;
  • 统计时排除前200个时间步的暂态数据,只计算稳态阶段的均值。

代码修改:

  1. 更新模拟参数:
sim_time <- 1000  # 延长模拟时间
warmup_time <- 200  # 暂态期长度
  1. 计算平均队长时过滤暂态数据:
# 只保留warmup_time之后的稳态数据
steady_state_data <- plot_data_queue %>% filter(Time > warmup_time)
mean(steady_state_data$QueueLength)

方案2:改用事件驱动模拟(更准确的连续时间模拟)

事件驱动模拟直接模拟到达和离开事件的发生时间,完全符合M/M队列的连续时间假设,消除离散时间步的近似误差。

修正后的事件驱动模拟函数:

run_event_driven_simulation <- function(num_servers) {
    current_time <- 0
    queue <- initial_queue_size
    processed <- 0
    server_busy_until <- rep(-Inf, num_servers)  # 记录每个服务器的空闲时间
    queue_length_history <- data.frame(time = numeric(), length = numeric())
    
    # 初始化第一个到达事件
    next_arrival <- rexp(1, lambda)
    
    while (current_time < sim_time) {
        # 找到下一个离开事件的时间
        next_departure <- min(server_busy_until[server_busy_until > current_time])
        if (is.infinite(next_departure)) next_departure <- Inf
        
        # 确定下一个事件类型
        if (next_arrival < next_departure) {
            # 处理到达事件
            time_diff <- next_arrival - current_time
            # 记录当前队列长度在这段时间内的持续时间
            if (current_time > 0) {
                queue_length_history <- rbind(queue_length_history, 
                                             data.frame(time = time_diff, length = queue))
            }
            current_time <- next_arrival
            queue <- queue + 1
            # 生成下一个到达事件
            next_arrival <- current_time + rexp(1, lambda)
            
            # 如果有空闲服务器,立即开始服务
            free_server <- which(server_busy_until <= current_time)[1]
            if (!is.na(free_server)) {
                service_time <- rexp(1, mu)
                server_busy_until[free_server] <- current_time + service_time
            }
        } else {
            # 处理离开事件
            time_diff <- next_departure - current_time
            queue_length_history <- rbind(queue_length_history, 
                                         data.frame(time = time_diff, length = queue))
            current_time <- next_departure
            queue <- queue - 1
            processed <- processed + 1
            
            # 如果队列还有顾客,安排下一个服务
            if (queue > 0) {
                free_server <- which(server_busy_until <= current_time)[1]
                service_time <- rexp(1, mu)
                server_busy_until[free_server] <- current_time + service_time
            }
        }
    }
    
    # 计算时间加权的平均队列长度(稳态)
    # 排除前warmup_time的暂态数据
    warmup_idx <- cumsum(queue_length_history$time) >= warmup_time
    steady_state <- queue_length_history[warmup_idx, ]
    avg_queue_length <- sum(steady_state$time * steady_state$length) / sum(steady_state$time)
    
    return(list(avg_queue_length = avg_queue_length, 
                queue_length_history = queue_length_history))
}

使用事件驱动模拟的计算:

# 执行多次模拟
event_results <- replicate(num_simulations, run_event_driven_simulation(1), simplify = FALSE)
# 提取所有模拟的平均队长
avg_lengths <- sapply(event_results, function(x) x$avg_queue_length)
# 计算均值
mean(avg_lengths)

该方法模拟结果会更接近理论值4,因为它完全贴合M/M队列的连续时间假设,且排除了暂态期。


内容的提问来源于stack exchange,提问作者stats_noob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 15:32:33