通过不同的跳过方法安排日期时间间隔

时间:2014-11-10 22:59:36

标签: python datetime scheduling intervals

我有一个日期时间间隔列表(开始和结束时间)。日期时间间隔具有一些其他属性(请参阅计划)。 由于排序,我已经有了一些间隔的提升计划。 现在我想实现一些方法来处理重叠冲突。 每次应该只运行一个任务。应跳过重叠任务,不得转移或延迟。

这些调度方法应该类似于

  • FCFS(先到先得):应该清楚
  • 优先级等属性的最大值
  • 事件的最长持续时间(应与最大值相似)

假设我们有像事件(间隔,优先级)这样的事件: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"])

我可能会破解所有方法,导致一些丑陋的代码。

有没有人(处理实现这些不同的日程安排要求而且)知道一种很好的方法吗?

2 个答案:

答案 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