我有一个日期时间间隔列表(开始和结束时间)。日期时间间隔具有一些其他属性(请参阅计划)。 由于排序,我已经有了一些间隔的提升计划。 现在我想实现一些方法来处理重叠冲突。 每次应该只运行一个任务。应跳过重叠任务,不得转移或延迟。
这些调度方法应该类似于
假设我们有像事件(间隔,优先级)这样的事件:A(0-7,2),B(5-10,3),C(8-15,1),D(20-25,0) )。 价值更高,优先级更高。
FCFS:A,C,D - 最高优先级:B,D - 最长持续时间:A,C,D
这是我对FCFS的第一种方法。我认为这也是一种糟糕的方法 - 对于其他方法,因为我需要进行反向查找,而不仅仅是最后一次事件。
示例数据:
start1 = datetime.now()
start2 = datetime.now() + timedelta(seconds=40)
start3 = datetime.now() + timedelta(seconds=70)
start4 = datetime.now() + timedelta(seconds=200)
schedule = [{"start": start1,
"end": start1 + timedelta(seconds=60),
"name": "Task1",
"attr": 2},
{"start": start2,
"end": start2 + timedelta(seconds=60),
"name": "Task2",
"attr": 3},
{"start": start3,
"end": start3 + timedelta(seconds=60),
"name": "Task3",
"attr": 1},
{"start": start4,
"end": start4 + timedelta(seconds=60),
"name": "Task4",
"attr": 0}
]
助手calss DateTimeInterval。对于差异,我使用了this。
class DateTimeInterval(object):
def __init__(self, start, end):
self.start = start
self.end = end
def __sub__(self, other):
latest_start = max(self.start, other.start)
earliest_end = min(self.end, other.end)
return earliest_end - latest_start
安排FCFS
# now we can order the beginnings
schedule_sorted = sorted(schedule, key=lambda x: (x["start"], x["name"]))
last = None
for job in schedule_sorted:
interval = DateTimeInterval(job["start"], job["end"])
# if there is a last entry
if last:
interval_last = DateTimeInterval(last["start"], last["end"])
diff = interval - interval_last
if diff.total_seconds() > 0:
logging.warn("%s CONFLICT OVERLAPPING %s!", job["name"], diff)
else:
last = job
else:
last = job
logging.info("%s: %s %s", job["name"], job["start"], job["end"])
我可能会破解所有方法,导致一些丑陋的代码。
有没有人(处理实现这些不同的日程安排要求而且)知道一种很好的方法吗?
答案 0 :(得分:1)
这应该让你开始,根据需要调整你的lambda函数。我只是告诉你如何做min,但max完全相似。 min的文档是here
ByFCFS = min(schedule,key=lambda k:k["start"])
ByAttr= min(schedule,key=lambda k:k["attr"])
ByTimeDiff = min(schedule,key=lambda k:k["end"]-k["start"])
>>> ByFCFS
{'start': datetime.datetime(2014, 11, 10, 20, 32, 54, 151000), 'end': datetime.datetime(2014, 11, 10, 20, 33, 54, 151000), 'name': 'Task1', 'attr': 2}
>>> ByAttr
{'start': datetime.datetime(2014, 11, 10, 20, 36, 14, 152000), 'end': datetime.datetime(2014, 11, 10, 20, 37, 14, 152000), 'name': 'Task4', 'attr': 0}
>>> ByTimeDiff
{'start': datetime.datetime(2014, 11, 10, 20, 32, 54, 151000), 'end': datetime.datetime(2014, 11, 10, 20, 33, 54, 151000), 'name': 'Task1', 'attr': 2}
>>>
请注意,如果ByTimeDiff的示例中有许多最小值,则会返回第一条记录。如果您需要执行max,请将min替换为max。
答案 1 :(得分:1)
鉴于您对其他方法的解释,我认为您应该改变您的方法。您应该首先按照分辨率标准(FCFS,最长持续时间或优先级)对事件进行排序,而不是按开始时间排序。然后,您应该有一个方法schedule_event()
,它可以将一个事件插入到已排序的已调度事件列表中,也可以删除事件。
我们进行的初始排序可确保首先调度所有优先级较高的事件,然后在发生冲突时删除优先级较低的事件。这里有一些骨架代码:
def sort_events(method_name, events):
######
return sorted_events
def schedule_event(event, scheduled_events):
if not len(scheduled_events):
scheduled_events.append(event)
return
right_index = bisect.bisect(scheduled_events, event)
left_index = right_index - 1
if len(scheduled_events) == right_index:
if event.conflicts(scheduled_events[left_index]):
return
else:
if event.conflicts(scheduled_events[left_index]) or event.conflicts(scheduled_events[right_index]):
return
bisect.insort(scheduled_events, event)
def main():
scheduled_events = []
sorted_events = sort_events("FCFS", events)
for event in sorted_events:
schedule_event(event, scheduled_events)
您应该按排序顺序维护scheduled_events
列表中的事件。按开始时间顺序维护它们。您可以使用bisect
module查看插入时是否存在任何冲突。使用bisect.bisect()
查找插入点并检查左边和右边的冲突。在左边,结束时间应该在当前事件的开始时间之前。在右边,开始时间应该在当前事件的结束时间之后。如果没有冲突,请使用bisect.insort()
Else插入,不执行任何操作。
另外,为了使排序成为可能,您需要定义自己的Event类而不是使用字典,并在该类中实现__lt__()
方法。
class Event:
def __init__(self, start_time, end_time):
self.start_time = start_time
self.end_time = end_time
def __lt__(self,):
pass