You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中创建带优先级的基于时间的任务队列?

嘿,这个需求很实际——既要按优先级调度任务,还要处理同时间段的高优先级任务覆盖低优先级的情况。既然你已经有了基础的优先级队列实现,咱们可以在这个基础上扩展时间冲突的检查和处理逻辑,下面是具体的实现思路和代码示例:

实现思路与代码示例

1. 定义可比较的任务结构

首先,我们需要把任务的时间范围、优先级、ID等信息封装成一个类,并且实现时间重叠检查和优先级比较的逻辑。这里用Python的dataclasses来简化类的定义:

from dataclasses import dataclass
from datetime import datetime
import queue

@dataclass(order=True)
class Job:
    priority: int  # 数值越小优先级越高(和你的示例一致)
    start_time: datetime
    end_time: datetime
    job_id: str

    def overlaps_with(self, other: 'Job') -> bool:
        """检查两个任务是否在同一天且时间段重叠"""
        if self.start_time.date() != other.start_time.date():
            return False
        # 时间段重叠的条件:A开始时间 < B结束时间 且 A结束时间 > B开始时间
        return self.start_time < other.end_time and self.end_time > other.start_time

注意:order=True会让Job类自动支持比较操作,PriorityQueue会根据这个比较结果进行堆排序,优先级数值越小的任务会排在前面。

2. 自定义带时间冲突处理的优先级队列

原生的PriorityQueue只负责按优先级排序,不会处理时间冲突,所以我们需要封装一个自定义队列,在添加任务时先检查冲突,再决定是否替换旧任务:

class TimePriorityQueue:
    def __init__(self):
        self._queue = queue.PriorityQueue()
        # 维护一个列表跟踪所有已添加的任务,方便冲突检查
        self._jobs = []

    def put(self, job: Job):
        # 先检查是否有冲突的任务
        conflicting_jobs = [j for j in self._jobs if job.overlaps_with(j)]
        should_add = True

        for existing_job in conflicting_jobs:
            if job.priority < existing_job.priority:
                # 新任务优先级更高,移除旧任务
                self._remove_job(existing_job)
            else:
                # 新任务优先级更低,直接放弃添加
                should_add = False

        if should_add:
            self._jobs.append(job)
            self._queue.put(job)

    def get(self) -> Job:
        job = self._queue.get()
        self._jobs.remove(job)
        return job

    def empty(self) -> bool:
        return self._queue.empty()

    def _remove_job(self, job_to_remove: Job):
        """从队列中移除指定任务(处理堆结构的局限性)"""
        # 原生PriorityQueue是堆结构,无法直接删除元素,所以先取出所有元素过滤后重新放入
        temp_jobs = []
        while not self._queue.empty():
            current_job = self._queue.get()
            if current_job != job_to_remove:
                temp_jobs.append(current_job)
        
        # 重新构建堆
        for job in temp_jobs:
            self._queue.put(job)
        
        # 从跟踪列表中移除
        self._jobs.remove(job_to_remove)

3. 测试你的示例场景

接下来我们用你给出的示例任务来测试这个队列:

def parse_time_string(time_str: str) -> tuple[datetime, datetime]:
    """解析"13:00-14:00 5.5.2018"格式的时间字符串为datetime对象"""
    time_range, date_part = time_str.split()
    start_time_str, end_time_str = time_range.split('-')
    day, month, year = map(int, date_part.split('.'))
    
    start_hour, start_minute = map(int, start_time_str.split(':'))
    end_hour, end_minute = map(int, end_time_str.split(':'))
    
    start_datetime = datetime(year, month, day, start_hour, start_minute)
    end_datetime = datetime(year, month, day, end_hour, end_minute)
    
    return start_datetime, end_datetime

# 创建示例任务
job1_start, job1_end = parse_time_string("13:00-14:00 5.5.2018")
job1 = Job(priority=10, start_time=job1_start, end_time=job1_end, job_id="Job 1")

job2_start, job2_end = parse_time_string("14:00-15:00 5.5.2018")
job2 = Job(priority=10, start_time=job2_start, end_time=job2_end, job_id="Job 2")

job3_start, job3_end = parse_time_string("14:00-15:00 5.5.2018")
job3 = Job(priority=1, start_time=job3_start, end_time=job3_end, job_id="Job 3")

# 测试队列
tpq = TimePriorityQueue()
tpq.put(job1)
tpq.put(job2)
tpq.put(job3)

# 依次取出任务,验证结果
print("任务取出顺序:")
while not tpq.empty():
    job = tpq.get()
    time_format = job.start_time.strftime("%H:%M-%H:%M %d.%m.%Y")
    print(f"- {job.job_id} | 优先级{job.priority} | 时间{time_format}")

运行这段代码,你会看到输出是:

任务取出顺序:
- Job 3 | 优先级1 | 时间14:00-15:00 05.05.2018
- Job 1 | 优先级10 | 时间13:00-14:00 05.05.2018

完全符合你的需求:Job3覆盖了同时间段的Job2,最终队列里只有Job3和Job1,且优先级高的Job3先被取出。

4. 关键逻辑说明

  • 时间重叠判断:overlaps_with方法是核心,确保只有同一天且时间段有重叠的任务才会触发覆盖逻辑。
  • 冲突处理:添加新任务时,会先检查所有现有任务,若新任务优先级更高,则移除旧任务;若优先级更低,则直接跳过添加。
  • 堆结构的局限性:原生PriorityQueue基于堆实现,不支持高效删除元素,所以我们采用了“取出所有元素过滤后重新放入”的方式。如果你的任务量很大,可以考虑用heapq模块自行维护堆结构,实现更高效的删除操作。

内容的提问来源于stack exchange,提问作者emir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:32:36