继续编写并完善资源池相关机制;

This commit is contained in:
Saturneric 2021-04-20 05:37:46 +08:00
parent c1a8cdedcd
commit 0ec006d423
4 changed files with 190 additions and 82 deletions

View File

@ -84,8 +84,14 @@ def import_resource(res) -> Dict[str, model.Resource]:
def import_resource_attributes(res, resources: Dict[str, model.Resource]): def import_resource_attributes(res, resources: Dict[str, model.Resource]):
for record in res: for record in res:
resources[record[0]].set_basic_attr(record[1]) resources[record[0]].set_basic_attr(record[2])
resources[record[0]].add_attr(record[2]) for attr in record[1].split(","):
resources[record[0]].add_attr(attr)
def import_process_resource(res, processes: Dict[str, model.Process]):
for record in res:
processes[record[0]].add_res_need(record[1], record[2])
def import_dataset(): def import_dataset():
@ -133,6 +139,11 @@ def import_dataset():
import_resource_attributes(res, resources) import_resource_attributes(res, resources)
cur.execute("SELECT * FROM aps_process_resource;")
res = cur.fetchall()
import_process_resource(res, processes)
conn.close() conn.close()
return orders, products, processes, resources return orders, products, processes, resources

View File

@ -63,7 +63,7 @@ class Process:
pcs_id: str, pcs_id: str,
pcs_name: str, pcs_name: str,
product: Product, product: Product,
workspace: Workspace): workspace: str):
self.pcs_id: str = pcs_id self.pcs_id: str = pcs_id
self.pcs_name: str = pcs_name self.pcs_name: str = pcs_name
@ -79,7 +79,7 @@ class Process:
self.last_pcs: Optional[Process] = None self.last_pcs: Optional[Process] = None
self.res_needs: List[Dict[str, any]] = [] self.res_needs: List[Dict[str, any]] = []
self.workspace: Workspace = workspace self.workspace: str = workspace
def set_pre_last_pcs(self, prev_pcs: Optional[Process], last_pcs: Optional[Process]): def set_pre_last_pcs(self, prev_pcs: Optional[Process], last_pcs: Optional[Process]):
self.prev_pcs: Process = prev_pcs self.prev_pcs: Process = prev_pcs

View File

@ -1,6 +1,8 @@
from __future__ import annotations
import model import model
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import List, Dict, Optional from typing import List, Dict, Optional
from copy import deepcopy
class RuntimeProduct: class RuntimeProduct:
@ -84,36 +86,43 @@ class RuntimeProcess:
# 运行时资源需求 # 运行时资源需求
class RuntimeResourceNeed: class RuntimeResourceNeed:
def __int__(self, def __init__(self, runtime_process: RuntimeProcess, resource_attr: str, workspace: str,
process: model.Process,
resource_attr: str,
workspace: str,
start: datetime, end: datetime): start: datetime, end: datetime):
if start < end: if start > end:
raise RuntimeError("the start time must before the end time") raise RuntimeError("the start time must before the end time")
self.process: model.Process = process self.process: model.Process = runtime_process.process
self.resource_attr: str = resource_attr self.resource_attr: str = resource_attr
self.workspace: str = workspace self.workspace: str = workspace
self.start: datetime = start self.start: datetime = start
self.end: datetime = end self.end: datetime = end
self.plan_alloc_resources_id: List[str] = []
self.could_alloc = False
self.ddl = runtime_process.ddl
def add_plan_alloc_resource(self, runtime_resource_id: str):
self.plan_alloc_resources_id.append(runtime_resource_id)
# 运行时资源 # 运行时资源
class RuntimeResource: class RuntimeResource:
def __init__(self, resource: model.Resource): def __init__(self, resource: model.Resource, start_time: datetime):
self.resource: model.Resource = resource self.resource: model.Resource = resource
self.workspace: str = self.resource.workspace self.workspace: str = self.resource.workspace
self.basic_attr = self.resource.basic_attr self.basic_attr = self.resource.basic_attr
self.resource_attrs = self.resource.attrs self.resource_attrs = self.resource.attrs
self.schedules: List[RuntimeResourceNeed] = [] self.schedules: List[RuntimeResourceNeed] = []
self.start_time: datetime = start_time
def add_schedule(self, schedule: RuntimeResourceNeed) -> bool: def add_schedule(self, schedule: RuntimeResourceNeed, do: bool) -> bool:
pre_need: Optional[RuntimeResourceNeed] = None pre_need: Optional[RuntimeResourceNeed] = None
back_need: Optional[RuntimeResourceNeed] = None back_need: Optional[RuntimeResourceNeed] = None
if schedule.ddl < self.start_time:
return False
for resource_need in self.schedules: for resource_need in self.schedules:
if resource_need.end > schedule.start: if resource_need.end > schedule.start:
pre_need = resource_need pre_need = resource_need
@ -124,6 +133,7 @@ class RuntimeResource:
if pre_need is not None or back_need is not None: if pre_need is not None or back_need is not None:
return False return False
else: else:
if do is True:
self.schedules.append(schedule) self.schedules.append(schedule)
self.schedules = sorted(self.schedules, key=lambda need: need.start) self.schedules = sorted(self.schedules, key=lambda need: need.start)
return True return True
@ -131,14 +141,14 @@ class RuntimeResource:
def get_earliest_available_free_times(self, duration: timedelta) -> datetime: def get_earliest_available_free_times(self, duration: timedelta) -> datetime:
# 没有已分配任务 # 没有已分配任务
if self.schedules == 0: if len(self.schedules) == 0:
return datetime.now() return self.start_time
# 只有一个已分配任务 # 只有一个已分配任务
if self.schedules == 1: if len(self.schedules) == 1:
target_schedule = self.schedules[0] target_schedule = self.schedules[0]
if datetime.now() < target_schedule.start: if self.start_time < target_schedule.start:
if target_schedule.start - datetime.now() > duration: if target_schedule.start - self.start_time > duration + timedelta(minutes=1):
return target_schedule.start - duration return target_schedule.start - duration
else: else:
@ -148,68 +158,130 @@ class RuntimeResource:
pre_schedule = self.schedules[i] pre_schedule = self.schedules[i]
back_schedule = self.schedules[i + 1] back_schedule = self.schedules[i + 1]
if datetime.now() < pre_schedule.start: if self.start_time < pre_schedule.start:
if pre_schedule.start - datetime.now() > duration: if pre_schedule.start - self.start_time > duration + timedelta(minutes=1):
return pre_schedule.start - duration return pre_schedule.start - duration - timedelta(minutes=1)
elif back_schedule.start - pre_schedule.end > duration: elif back_schedule.start - pre_schedule.end > duration + timedelta(minutes=1):
return pre_schedule.end return pre_schedule.end
return self.schedules[-1].end return self.schedules[-1].end
# 资源池
class RuntimeResourcePool: class RuntimeResourcePool:
def __init__(self, resources: List[model.Resource]): def __init__(self, resources: List[model.Resource], start_time: datetime):
self.pool: List[RuntimeResource] = [] self.pool: Dict[str, RuntimeResource] = {}
self.start_time: datetime = start_time
for resource in resources: for resource in resources:
runtime_resource = RuntimeResource(resource) runtime_resource = RuntimeResource(resource, self.start_time)
self.pool.append(runtime_resource) self.pool[runtime_resource.resource.rsc_id] = runtime_resource
# 资源分配操作
def alloc_resource(self, resource_needs: List[RuntimeResourceNeed]):
for resource_need in resource_needs:
if resource_need.could_alloc is False:
continue
for plan_alloc_resource_id in resource_need.plan_alloc_resources_id:
self.pool[plan_alloc_resource_id].add_schedule(resource_need, True)
def try_alloc_resource(self, resource_needs: List[RuntimeResourceNeed]) -> bool:
temp_pool = deepcopy(list(self.pool.values()))
# 已经满足的需求
fulfilled_needs = []
if_all_alloc = True
for resource_need in resource_needs:
if resource_need.could_alloc is True:
continue
def alloc_resource(self, resource_need: RuntimeResourceNeed) -> bool:
# 精确搜索 # 精确搜索
for runtime_resource in self.pool: for runtime_resource in temp_pool:
# 排除不同车间 # 排除不同车间
if runtime_resource.workspace != resource_need.workspace: if runtime_resource.workspace != resource_need.workspace:
continue continue
if runtime_resource.basic_attr == resource_need.resource_attr: if runtime_resource.basic_attr == resource_need.resource_attr:
if runtime_resource.add_schedule(resource_need) is True: if runtime_resource.add_schedule(resource_need, False) is True:
return True resource_need.add_plan_alloc_resource(runtime_resource.resource.rsc_id)
fulfilled_needs.append(resource_need)
runtime_resource.add_schedule(resource_need, True)
resource_need.could_alloc = True
break
# 是否已经分配完成
if resource_need.could_alloc is False:
# 放宽条件搜索 # 放宽条件搜索
for runtime_resource in self.pool: for runtime_resource in temp_pool:
# 排除不同车间 # 排除不同车间
if runtime_resource.workspace != resource_need.workspace: if runtime_resource.workspace != resource_need.workspace:
continue continue
if resource_need.resource_attr in runtime_resource.resource_attrs: if resource_need.resource_attr in runtime_resource.resource_attrs:
if runtime_resource.add_schedule(resource_need) is True: if runtime_resource.add_schedule(resource_need, False) is True:
return True resource_need.add_plan_alloc_resource(runtime_resource.resource.rsc_id)
fulfilled_needs.append(resource_need)
runtime_resource.add_schedule(resource_need, True)
resource_need.could_alloc = True
break
return False if resource_need not in fulfilled_needs:
if_all_alloc = False
def get_earliest_free_time(self, resource_need: RuntimeResourceNeed) -> datetime: return if_all_alloc
def reset_earliest_free_start_time(self, resource_needs: List[RuntimeResourceNeed]) -> bool:
if_found = False
for resource_need in resource_needs:
if resource_need.could_alloc is True:
continue
earliest_time: Optional[datetime] = None earliest_time: Optional[datetime] = None
duration = resource_need.end - resource_need.start duration = resource_need.end - resource_need.start
# 精确搜索 # 精确搜索
for runtime_resource in self.pool: for runtime_resource in self.pool.values():
# 排除不同车间
if runtime_resource.workspace != resource_need.workspace:
continue
if runtime_resource.basic_attr == resource_need.resource_attr: if runtime_resource.basic_attr == resource_need.resource_attr:
temp_earliest_time = runtime_resource.get_earliest_available_free_times(duration) temp_earliest_time = runtime_resource.get_earliest_available_free_times(duration)
# 时间不能超过DDL
if temp_earliest_time > resource_need.ddl - duration:
continue
if earliest_time is None or earliest_time > temp_earliest_time: if earliest_time is None or earliest_time > temp_earliest_time:
earliest_time = temp_earliest_time earliest_time = temp_earliest_time
# 优先利用对口资源 # 优先利用对口资源
if earliest_time is not None: if earliest_time is not None:
return earliest_time resource_need.start = earliest_time
# 放宽条件搜索 # 放宽条件搜索
for runtime_resource in self.pool: else:
for runtime_resource in self.pool.values():
# 排除不同车间
if runtime_resource.workspace != resource_need.workspace:
continue
if resource_need.resource_attr in runtime_resource.resource_attrs: if resource_need.resource_attr in runtime_resource.resource_attrs:
temp_earliest_time = runtime_resource.get_earliest_available_free_times(duration) temp_earliest_time = runtime_resource.get_earliest_available_free_times(duration)
# 时间不能超过DDL
if temp_earliest_time > resource_need.ddl - duration:
continue
if earliest_time is None or earliest_time > temp_earliest_time: if earliest_time is None or earliest_time > temp_earliest_time:
earliest_time = temp_earliest_time earliest_time = temp_earliest_time
return earliest_time if earliest_time is None:
if_found = False
else:
resource_need.start = earliest_time
resource_need.end = earliest_time + duration
if_found = True
return if_found

View File

@ -2,7 +2,7 @@ import runtime
import model import model
import csv import csv
from typing import List, Dict from typing import List, Dict
from datetime import datetime from datetime import datetime, timedelta, date
import time import time
import math import math
import dataset_importer import dataset_importer
@ -33,14 +33,12 @@ def orders_processor(orders: Dict[str, model.Order]) -> List[runtime.RuntimeProd
def search_semi_products(floor, produce_tree, produce_list, runtime_product): def search_semi_products(floor, produce_tree, produce_list, runtime_product):
runtime_semi_products = [] runtime_semi_products = []
produce_tree.append({"runtime_product": runtime_product, "runtime_semi_products": runtime_semi_products}) produce_tree.append({"runtime_product": runtime_product, "runtime_semi_products": runtime_semi_products})
# print("F", runtime_product.product.product_id, runtime_product.ddl) # print("F", runtime_product.product.product_id, runtime_product.ddl)
if len(runtime_product.product.semi_products) > 0: if len(runtime_product.product.semi_products) > 0:
for item in runtime_product.product.semi_products: for item in runtime_product.product.semi_products:
runtime_semi_product = runtime.RuntimeProduct(item["semi_product"], item["amount"]) runtime_semi_product = runtime.RuntimeProduct(item["semi_product"], item["amount"])
runtime_semi_product.set_ddl_start(runtime_product.ddl, runtime_product.start) runtime_semi_product.set_ddl_start(runtime_product.ddl, runtime_product.start)
@ -48,12 +46,11 @@ def search_semi_products(floor, produce_tree, produce_list, runtime_product):
search_semi_products(floor + 1, runtime_semi_products, produce_list, runtime_semi_product) search_semi_products(floor + 1, runtime_semi_products, produce_list, runtime_semi_product)
print("L", floor, runtime_product.product.product_id, runtime_product.ddl) # print("L", floor, runtime_product.product.product_id, runtime_product.ddl)
produce_list.append(runtime_product) produce_list.append(runtime_product)
def products_processor(runtime_products: List[runtime.RuntimeProduct]): def products_processor(runtime_products: List[runtime.RuntimeProduct]):
runtime_products_processes_list: List[Dict[str, any]] = [] runtime_products_processes_list: List[Dict[str, any]] = []
for runtime_product in runtime_products: for runtime_product in runtime_products:
@ -80,25 +77,53 @@ def products_processor(runtime_products: List[runtime.RuntimeProduct]):
for item in runtime_products_processes_list: for item in runtime_products_processes_list:
for runtime_process in item["runtimeProcess"]: for runtime_process in item["runtimeProcess"]:
runtime_product: runtime.RuntimeProduct = item["runtimeProduct"] runtime_product: runtime.RuntimeProduct = item["runtimeProduct"]
print(runtime_product.product.product_id, runtime_product.delay, runtime_process.process.pcs_id) # print(runtime_product.product.product_id, runtime_product.delay, runtime_process.process.pcs_id)
return runtime_products_processes_list return runtime_products_processes_list
# def resource_processor(resources: List[model.Resource], runtime_products_processes_list: List[Dict[str, any]]): def resource_processor(runtime_products_processes_list: List[Dict[str, any]],
# resource_pool = runtime.RuntimeResourcePool(resources) resource_pool: runtime.RuntimeResourcePool,
# start_time: datetime):
# for item in runtime_products_processes_list: could_alloc = True
# ifalloc = True
# for runtime_process in item["runtimeProcess"]: for item in runtime_products_processes_list:
# runtime_process: runtime.RuntimeProcess = runtime_process runtime_resource_needs: List[runtime.RuntimeResourceNeed] = []
# for resource_item in runtime_process.process.res_needs: for runtime_process in item["runtimeProcess"]:
# resource_item[''] runtime_process: runtime.RuntimeProcess = runtime_process
# runtime_resource_need = runtime.RuntimeResourceNeed(runtime_process.process) for resource_item in runtime_process.process.res_needs:
# if resource_pool.alloc_resource(): resource_attr = resource_item["rcs_attr"]
amount = resource_item["amount"]
for i in range(amount):
runtime_resource_need: runtime.RuntimeResourceNeed = runtime.RuntimeResourceNeed(
runtime_process,
resource_attr,
runtime_process.process.workspace,
start_time,
start_time + timedelta(minutes=runtime_process.process.pdt_time))
runtime_resource_needs.append(runtime_resource_need)
if resource_pool.try_alloc_resource(runtime_resource_needs):
resource_pool.alloc_resource(runtime_resource_needs)
else:
while resource_pool.reset_earliest_free_start_time(runtime_resource_needs):
resource_pool.try_alloc_resource(runtime_resource_needs)
resource_pool.alloc_resource(runtime_resource_needs)
for runtime_resource_need in runtime_resource_needs:
if runtime_resource_need.could_alloc is False:
could_alloc = False
break
return could_alloc
if __name__ == "__main__": if __name__ == "__main__":
start_time: datetime = datetime.combine(date(2020, 8, 12), datetime.min.time())
m_orders, m_products, m_processes, m_resources = dataset_importer.import_dataset() m_orders, m_products, m_processes, m_resources = dataset_importer.import_dataset()
resource_pool: runtime.RuntimeResourcePool = runtime.RuntimeResourcePool(m_resources.values(), start_time)
produce_list = orders_processor(m_orders) produce_list = orders_processor(m_orders)
products_processor(produce_list) rt_rcs_list = products_processor(produce_list)
print(resource_processor(rt_rcs_list, resource_pool, start_time))