Simpy资源首次请求释放后无法再次可用问题排查
问题:Simpy工厂仿真中machine_a仅使用一次后无法再被调度
场景描述
仿真两台机器machine_a和machine_b的工厂加工流程,两台机器加工时长不同。运行后发现machine_a仅在初始阶段被使用一次,1.00时刻释放后,后续工序始终只使用machine_b,即使machine_a处于空闲状态。排查发现machine_a的用户列表为空,但请求队列异常增长,强制指定使用machine_a会导致仿真终止。
问题根源
核心问题在于未正确处理未被选中的资源请求:
- 在
process_order的循环中,每次都会同时向machine_a和machine_b发送请求 - 当
env.any_of返回已满足的请求后,未被选中的请求并未被取消,而是一直留在资源的请求队列中 - 随着循环推进,
machine_a的请求队列积压大量未处理的旧请求,新的请求永远排在队列末尾,无法被调度
修复方案
在选中目标机器后,需要调用resource.cancel(request)来取消所有未被接受的请求,而不是用release(release仅适用于已占用的资源)。
修复后的完整代码
import simpy import numpy as np import pandas as pd data = { 'operation_id': ['part_A_1', 'part_A_1', 'part_A_2', 'part_A_2', 'part_A_3', 'part_A_3', 'part_B_1', 'part_B_1', 'part_B_2', 'part_B_2', 'part_C_1', 'part_C_1', 'part_D_1', 'part_D_1', 'part_D_2', 'part_D_2'], 'workstation_id': ['machine_a', 'machine_b', 'machine_a', 'machine_b', 'machine_a', 'machine_b', 'machine_a', 'machine_b', 'machine_a', 'machine_b', 'machine_a', 'machine_b', 'machine_a', 'machine_b', 'machine_a', 'machine_b'], 'processing_time': [1.0, 1.3, 0.8, 1.1, 1.0, 1.2, 1.3, 1.0, 1.1, 3.0, 3.3, 1.0, 5.1, 9.5, 10.3, 5.0] } def process_order(env, workstations, operations_schedule): while len(operations_schedule) > 0: component_to_process = operations_schedule[0] # 同时请求两台机器 requests = {name: resource.request() for name, resource in workstations.items()} # 等待任意一台机器可用 accepted_requests = yield env.any_of(requests.values()) # 区分已接受和未接受的请求 accepted_names = [name for name, req in requests.items() if req in accepted_requests] rejected_names = [name for name, req in requests.items() if req not in accepted_requests] # 选中第一台可用机器 selected_machine = accepted_names[0] selected_request = requests[selected_machine] # 取消所有未被接受的请求(关键修复) for name in rejected_names: workstations[name].cancel(requests[name]) # 释放多余的已接受请求(如果有多台同时可用) if len(accepted_names) > 1: for name in accepted_names[1:]: workstations[name].release(requests[name]) print(f"Component {component_to_process} starts processing at {env.now:.2f} at {selected_machine}") # 获取对应加工时长 processing_time = processing_times[ (processing_times['operation_id'] == component_to_process) & (processing_times['workstation_id'] == selected_machine) ]['processing_time'].item() # 启动加工流程 env.process(machine_process( env=env, machine=selected_machine, processing_time=processing_time, component_to_process=component_to_process, request_to_release=selected_request )) operations_schedule.pop(0) def machine_process(env, machine, processing_time, component_to_process, request_to_release): yield env.timeout(processing_time) print(f"{component_to_process} finished at time {env.now:.2f} at {machine}") workstations[machine].release(request_to_release) processing_times = pd.DataFrame(data) operations_schedule = processing_times['operation_id'].drop_duplicates().tolist() env = simpy.Environment() workstations = {'machine_a': simpy.Resource(env, capacity=1), 'machine_b': simpy.Resource(env, capacity=1)} env.process(process_order(env=env, workstations=workstations, operations_schedule=operations_schedule)) env.run()
修复后的运行输出
Component part_A_1 starts processing at 0.00 at machine_a Component part_A_2 starts processing at 0.00 at machine_b part_A_1 finished at time 1.00 at machine_a part_A_2 finished at time 1.10 at machine_b Component part_A_3 starts processing at 1.10 at machine_a part_A_3 finished at time 2.10 at machine_a Component part_B_1 starts processing at 2.10 at machine_a part_B_1 finished at time 3.40 at machine_a Component part_B_2 starts processing at 3.40 at machine_a part_B_2 finished at time 4.50 at machine_a Component part_C_1 starts processing at 4.50 at machine_a part_C_1 finished at time 7.80 at machine_a Component part_D_1 starts processing at 7.80 at machine_a part_D_1 finished at time 12.90 at machine_a Component part_D_2 starts processing at 12.90 at machine_a part_D_2 finished at time 23.20 at machine_a
可以看到,machine_a在释放后被正常调度,不再出现闲置的情况。
内容的提问来源于stack exchange,提问作者Chorrelino
相关产品推荐
相关产品推荐

