我想模拟一个需要执行一系列操作的工厂。有两台机器可以执行这些步骤,但每台机器的执行时间不同。
我的问题是 machine_a 仅使用一次,然后它就永远不再可用,即使我可以看到没有用户。
代码包含所有数据,因此您可以轻松运行它。
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:
# Parts will be processed in order
component_to_process = operations_schedule[0]
# Request all machines
requests = {name:resource.request() for name, resource in workstations.items()}
# Proceed when any of them is available
accepted_requests = yield env.any_of(requests.values())
# get the request dictionary containing only accepted requests
available_resources_names = [name for name, request in requests.items() if request in accepted_requests]
available_resources = {name:request for name, request in requests.items()if request in accepted_requests}
# For this case, we always select the first machine in the request list:
selected_machine = available_resources_names[0]
# if more than one machine is available, seize only the first one in the list and release the rest
if len(available_resources) > 1:
# Release all resources after the first one
for i in range(1, len(available_resources)):
request_name = available_resources_names[i] # this contains the name of the ith requested machine
request_object = available_resources[request_name]
workstations[request_name].release(request_object)
# Now that we know the workstation, we can calculate the processing time with random sampling
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()
# launch machinning process
env.process(machine_process(env = env,
machine = selected_machine,
processing_time = processing_time,
component_to_process=component_to_process,
request_to_release = available_resources[selected_machine]))
operations_schedule.pop(0)
# Process a single part
def machine_process(env, machine, processing_time, component_to_process, request_to_release):
# we wait for machine_a to be available
yield env.timeout(processing_time)
print(f"{component_to_process} finised at time {env.now:.2f} at {machine}")
# release the machine once it's processed
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 finised at time 1.00 at machine_a
part_A_2 finised at time 1.10 at machine_b
Component part_A_3 starts processing at 1.10 at machine_b
part_A_3 finised at time 2.30 at machine_b
Component part_B_1 starts processing at 2.30 at machine_b
part_B_1 finised at time 3.30 at machine_b
Component part_B_2 starts processing at 3.30 at machine_b
part_B_2 finised at time 6.30 at machine_b
Component part_C_1 starts processing at 6.30 at machine_b
part_C_1 finised at time 7.30 at machine_b
Component part_D_1 starts processing at 7.30 at machine_b
part_D_1 finised at time 16.80 at machine_b
Component part_D_2 starts processing at 16.80 at machine_b
part_D_2 finised at time 21.80 at machine_b
如果您看到,machine_a 在时间 1.00 变得可用,但在 machine_b 可用之前不会发生任何其他事情
我检查了资源上的队列,在machine_a上似乎在增长,释放请求有时有效果,使队列变短,但没有帮助。
如果我尝试强制 machine_a 进行稍后的迭代,则运行将在此时结束。
我查看了machine_a的用户,资源释放后为空。
当选择了多个资源时,您得到了用例,但是当只选择一个请求时,您仍然需要取消另一个请求,否则它最终会占用资源,但永远不会释放它。
这里有一个修复方法
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:
# Parts will be processed in order
component_to_process = operations_schedule[0]
# Request all machines
requests = {name:resource.request() for name, resource in workstations.items()}
# Proceed when any of them is available
accepted_requests = yield env.any_of(requests.values())
#------------------------------------- fix ----------------------------------
# need to cancel requests that are still open
open_requests = [request for name, request in requests.items() if requests not in accepted_requests]
for request in open_requests:
request.cancel()
# get the request dictionary containing only accepted requests
available_resources_names = [name for name, request in requests.items() if request in accepted_requests]
available_resources = {name:request for name, request in requests.items()if request in accepted_requests}
# For this case, we always select the first machine in the request list:
selected_machine = available_resources_names[0]
# if more than one machine is available, seize only the first one in the list and release the rest
if len(available_resources) > 1:
# Release all resources after the first one
for i in range(1, len(available_resources)):
request_name = available_resources_names[i] # this contains the name of the ith requested machine
request_object = available_resources[request_name]
workstations[request_name].release(request_object)
# Now that we know the workstation, we can calculate the processing time with random sampling
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()
# launch machinning process
env.process(machine_process(env = env,
machine = selected_machine,
processing_time = processing_time,
component_to_process=component_to_process,
request_to_release = available_resources[selected_machine]))
operations_schedule.pop(0)
# Process a single part
def machine_process(env, machine, processing_time, component_to_process, request_to_release):
# we wait for machine_a to be available
yield env.timeout(processing_time)
print(f"{component_to_process} finised at time {env.now:.2f} at {machine}")
# release the machine once it's processed
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()