基于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
相关产品推荐
相关产品推荐

