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

基于SimPy的M/M/1排队仿真问题:客户Departure逻辑异常

排查M/M/1排队仿真的离开逻辑异常问题

问题描述

我希望实现一个简单的M/M/1排队仿真,后续计划聚焦M/M/C模型并推导更多通用结果。最初从包含客户弃队的复杂模型入手,简化为M/M/1模型后,发现客户到达正常,但Departure(离开)逻辑异常,部分客户无法正确离开系统。

原代码

import random
import simpy
import numpy
from random import seed
import statistics
seed(29384)  # for seed of randint function
random_seed = 42  # for seed of other random generators
new_customers = 10  # Total number of customers in the system
interarrival = numpy.random.poisson(6, size=None)  # Generate new customers roughly every x seconds
waitingTimes = []
serviceTimes = []
interarrivalTimes = []

def generator(env, number, interval, server):  # customer generator with interarrival times.
    """generator generates customers randomly"""
    for i in range(number):
        c = customer(env, 'Customer%02d' % i, server, service_time=random.expovariate(0.15))
        env.process(c)
        t = random.expovariate(1.0 / interval)
        yield env.timeout(t)  # adds time to the counter, does not delete from the memory

def customer(env, name, server, service_time):
    # customer arrives to the system, waits and leaves
    arrive = env.now
    print('%7.4f : Arrival time of %s' % (arrive, name))
    with server.request() as req:
        results = yield req | env.timeout(arrive)
        
        if req in results:
            servertime = service_time
            yield env.timeout(servertime)
            serviceTimes.append(servertime)
            print('%7.4f Departure Time of %s' % (env.now, name))
            print('%7.4f Time Spent in the system of %s' % (env.now - arrive, name))
        else:
            waiting_time = env.now - arrive
            waitingTimes.append(waiting_time)
            print('%6.3f Waiting time of %s' % (waiting_time, name))

random.seed(random_seed)
env = simpy.Environment()
server = simpy.Resource(env, capacity=1)  # capacity changes the number of generators in the system.
env.process(generator(env, new_customers, interarrival, server))
env.run()
interarrivalTimes.append(interarrival)
average_interarrival = statistics.mean(interarrivalTimes)
average_waitingTime = statistics.mean(waitingTimes)
average_serviceTime = statistics.mean(serviceTimes)
print("Average Interravial Time Is : %7.4f" % (average_interarrival))
print("Average Waiting Time Is : %7.4f" % (average_waitingTime))
print("Average Service Time Is : %7.4f" % (average_serviceTime))

print("Elements of given array: ")
for i in range(0, len(interarrivalTimes)):
    print(interarrivalTimes[i]),

问题分析

  • 弃队逻辑错误:yield req | env.timeout(arrive)中,arrive是客户到达时的系统时间,这导致超时时间等于到达时间,客户刚进入系统就触发弃队,完全没机会等待服务,是部分客户无法正常离开的核心原因。如果是纯M/M/1模型,不需要弃队逻辑,应直接等待服务器空闲;若需保留弃队,需设置合理的最大等待时长(如固定值或符合分布的随机值)。
  • 到达间隔生成错误:numpy.random.poisson(6, size=None)仅生成单个数值,所有客户的到达间隔都用这个固定值,不符合M/M/1模型中到达间隔服从指数分布的定义(原代码generator中用了指数分布,但依赖的interval是单个泊松值,逻辑矛盾)。
  • 随机种子管理混乱:同时使用seed(29384)和random.seed(random_seed),会干扰随机数生成的一致性,建议统一设置种子。
  • 到达间隔收集错误:interarrivalTimes.append(interarrival)仅收集了初始的单个泊松值,未记录每个客户实际的到达间隔时间。

修正后的代码

版本1:纯M/M/1排队模型(无弃队)

移除错误的弃队逻辑,严格遵循M/M/1模型假设(到达间隔指数分布、服务时间指数分布、单服务器):

import random
import simpy
import statistics

# 统一设置随机种子
random_seed = 42
random.seed(random_seed)

new_customers = 10
avg_interarrival = 6  # 平均到达间隔(秒)
avg_service = 1/0.15  # 平均服务时间(与expovariate参数对应,lambda=0.15则均值为1/0.15)

waiting_times = []
service_times = []
interarrival_times = []

def generator(env, number, avg_interval, server):
    """生成客户,到达间隔服从指数分布"""
    prev_arrival_time = 0
    for i in range(number):
        # 生成到达间隔
        interarrival = random.expovariate(1.0 / avg_interval)
        yield env.timeout(interarrival)
        
        current_arrival_time = env.now
        # 记录到达间隔(第一个客户的间隔为0)
        if i > 0:
            interarrival_times.append(current_arrival_time - prev_arrival_time)
        prev_arrival_time = current_arrival_time
        
        # 创建客户进程
        env.process(customer(env, f'Customer{i:02d}', server))

def customer(env, name, server):
    arrive = env.now
    print(f'{arrive:7.4f} : Arrival time of {name}')
    
    with server.request() as req:
        # 等待服务器空闲
        yield req
        
        # 记录等待时间(到达时间到开始服务的时间差)
        waiting_time = env.now - arrive
        waiting_times.append(waiting_time)
        
        # 生成服务时间(指数分布)
        service_time = random.expovariate(0.15)
        service_times.append(service_time)
        
        # 模拟服务过程
        yield env.timeout(service_time)
        
        # 记录离开时间和系统逗留时间
        depart = env.now
        print(f'{depart:7.4f} Departure Time of {name}')
        print(f'{depart - arrive:7.4f} Time Spent in the system of {name}')

# 启动仿真
env = simpy.Environment()
server = simpy.Resource(env, capacity=1)
env.process(generator(env, new_customers, avg_interarrival, server))
env.run()

# 计算并输出统计结果
print("\n--- 仿真统计结果 ---")
print(f"Average Interarrival Time: {statistics.mean(interarrival_times):7.4f}")
print(f"Average Waiting Time: {statistics.mean(waiting_times):7.4f}")
print(f"Average Service Time: {statistics.mean(service_times):7.4f}")
print(f"Average Time in System: {statistics.mean([w+s for w,s in zip(waiting_times, service_times)]):7.4f}")

版本2:带合理弃队逻辑的M/M/1模型

如果需要保留客户弃队功能,将超时时间设置为合理的最大等待时长(例如固定值或服从某分布的随机值):

import random
import simpy
import statistics

random_seed = 42
random.seed(random_seed)

new_customers = 10
avg_interarrival = 6
avg_service = 1/0.15
max_wait_time = 10  # 客户最大等待时长,超时则弃队

waiting_times = []
service_times = []
interarrival_times = []
abandoned_count = 0

def generator(env, number, avg_interval, server):
    prev_arrival_time = 0
    for i in range(number):
        interarrival = random.expovariate(1.0 / avg_interval)
        yield env.timeout(interarrival)
        
        current_arrival_time = env.now
        if i > 0:
            interarrival_times.append(current_arrival_time - prev_arrival_time)
        prev_arrival_time = current_arrival_time
        
        env.process(customer(env, f'Customer{i:02d}', server))

def customer(env, name, server):
    global abandoned_count
    arrive = env.now
    print(f'{arrive:7.4f} : Arrival time of {name}')
    
    with server.request() as req:
        # 等待服务器空闲 或 超时弃队
        results = yield req | env.timeout(max_wait_time)
        
        if req in results:
            # 成功获得服务
            waiting_time = env.now - arrive
            waiting_times.append(waiting_time)
            
            service_time = random.expovariate(0.15)
            service_times.append(service_time)
            
            yield env.timeout(service_time)
            
            depart = env.now
            print(f'{depart:7.4f} Departure Time of {name}')
            print(f'{depart - arrive:7.4f} Time Spent in the system of {name}')
        else:
            # 超时弃队
            abandoned_count += 1
            print(f'{env.now:7.4f} {name} abandoned after waiting {env.now - arrive:.4f} seconds')

env = simpy.Environment()
server = simpy.Resource(env, capacity=1)
env.process(generator(env, new_customers, avg_interarrival, server))
env.run()

print("\n--- 仿真统计结果 ---")
print(f"Average Interarrival Time: {statistics.mean(interarrival_times):7.4f}")
if waiting_times:
    print(f"Average Waiting Time (served customers): {statistics.mean(waiting_times):7.4f}")
print(f"Average Service Time: {statistics.mean(service_times):7.4f}")
print(f"Number of Abandoned Customers: {abandoned_count}")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 22:18:29