Simply 资源在第一次请求释放后永远不可用

问题描述 投票:0回答:1

我想模拟一个需要执行一系列操作的工厂。有两台机器可以执行这些步骤,但每台机器的执行时间不同。

我的问题是 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的用户,资源释放后为空。

resources simpy anyof
1个回答
0
投票

当选择了多个资源时,您得到了用例,但是当只选择一个请求时,您仍然需要取消另一个请求,否则它最终会占用资源,但永远不会释放它。

这里有一个修复方法

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()
© www.soinside.com 2019 - 2024. All rights reserved.