From 001416e3996c6694aac742252f55b714431fcc94 Mon Sep 17 00:00:00 2001 From: ViperEkura <3081035982@qq.com> Date: Thu, 30 Apr 2026 15:43:18 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BF=AE=E6=94=B9=E5=AE=9E?= =?UTF-8?q?=E9=AA=8C=E6=AD=A5=E9=AA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- experiment/code/base.py | 368 +++++++++++++++++++++++++++++++----- experiment/code/fcfs.py | 100 ++++++++-- experiment/code/hrrn.py | 113 +++++++---- experiment/code/main.py | 36 +++- experiment/code/mlfq.py | 161 ++++++++++------ experiment/code/priority.py | 139 +++++++------- experiment/code/rr.py | 129 +++++++++---- experiment/code/sjf.py | 146 +++++++------- 8 files changed, 852 insertions(+), 340 deletions(-) diff --git a/experiment/code/base.py b/experiment/code/base.py index 4393f44..653cbc6 100644 --- a/experiment/code/base.py +++ b/experiment/code/base.py @@ -10,11 +10,32 @@ from typing import List, Dict, Optional @dataclass class Process: - """进程数据结构""" + """进程数据结构 + + 新增 IO 模拟字段: + cpu_bursts: CPU 计算时间段列表 (交替: CPU->IO->CPU->IO...) + io_bursts: IO 操作时间段列表 + io_wait: 进程在 IO 设备上等待的时间 (阻塞时间) + + 示例: + cpu_bursts = [5, 3, 2] # 3段CPU计算时间 + io_bursts = [2, 1] # 2次IO操作 + 进程执行顺序: CPU(5) -> IO(2) -> CPU(3) -> IO(1) -> CPU(2) + """ pid: str arrival_time: int = 0 - burst_time: int = 0 + burst_time: int = 0 # 总CPU时间 = sum(cpu_bursts) priority: int = 0 # 数值越小优先级越高 + + # ========== 新增 IO 模拟字段 ========== + cpu_bursts: List[int] = field(default_factory=list) # CPU计算时间段 + io_bursts: List[int] = field(default_factory=list) # IO操作时间段 + io_wait: int = 0 # IO设备等待时间 + is_io_bound: bool = False # 是否为IO密集型进程 + starts_with_io: bool = False # 是否以IO开始(默认False=先CPU) + # ===================================== + + # 调度相关状态 remaining_time: int = field(default=0) start_time: int = -1 completion_time: int = 0 @@ -22,9 +43,28 @@ class Process: turnaround_time: int = 0 weighted_turnaround_time: float = 0.0 # 带权周转时间 = 周转时间/服务时间 response_time: int = 0 + io_blocked_time: int = 0 # 因等待IO而阻塞的时间 def __post_init__(self): self.remaining_time = self.burst_time + # 如果没有指定 cpu_bursts,使用 burst_time 作为单段CPU时间 + if not self.cpu_bursts and self.burst_time > 0: + self.cpu_bursts = [self.burst_time] + + @property + def total_cpu_time(self) -> int: + """总CPU计算时间""" + return sum(self.cpu_bursts) if self.cpu_bursts else self.burst_time + + @property + def total_io_time(self) -> int: + """总IO操作时间""" + return sum(self.io_bursts) if self.io_bursts else 0 + + @property + def num_io_operations(self) -> int: + """IO操作次数""" + return len(self.io_bursts) def reset(self): """重置进程状态""" @@ -35,18 +75,92 @@ class Process: self.turnaround_time = 0 self.weighted_turnaround_time = 0.0 self.response_time = 0 + self.io_blocked_time = 0 class ProcessScheduler: - """进程调度器基类""" + """进程调度器基类 (支持IO模拟)""" + + # 进程状态 + STATUS_NEW = 'NEW' + STATUS_READY = 'READY' + STATUS_RUNNING = 'RUNNING' + STATUS_IO_WAIT = 'IO_WAIT' # 等待IO完成 + STATUS_TERMINATED = 'TERMINATED' def __init__(self, processes: List[Process]): self.processes = [p for p in processes] self.results: List[Process] = [] + self.gantt_chart: List[tuple] = [] # 甘特图记录 (时间, PID, 事件) + + # IO 模拟相关 + self.io_queue: List[Process] = [] # IO 等待队列 (等待IO完成的进程) + self.io_completion_events: List[tuple] = [] # IO 完成事件 (时间, 进程) + + def init_process(self, p: Process, current_time: int): + """初始化进程状态""" + p.status = self.STATUS_READY + p.current_cpu_idx = 0 # 当前执行的 cpu_burst 索引 + p.current_io_idx = -1 # 当前等待的 io_burst 索引 (-1表示未进入IO) + p.remaining_cpu_time = sum(p.cpu_bursts) if p.cpu_bursts else p.burst_time + p.io_wait_time = 0 # 累计IO等待时间 + if p.start_time == -1: + p.start_time = current_time + + def execute_cpu(self, p: Process, time_slice: int, current_time: int): + """执行一段 CPU burst""" + if p.current_cpu_idx >= len(p.cpu_bursts): + return 0 # 没有更多CPU burst + + cpu_burst = p.cpu_bursts[p.current_cpu_idx] + execute_time = min(time_slice, cpu_burst) + + p.remaining_cpu_time -= execute_time + + # 记录甘特图 + self.gantt_chart.append((current_time, p.pid, 'CPU', execute_time)) + + if execute_time >= cpu_burst: + # CPU burst 执行完毕 + p.current_cpu_idx += 1 + + # 检查是否有对应的 IO burst + if p.current_cpu_idx - 1 < len(p.io_bursts): + # 进入 IO 等待 + io_time = p.io_bursts[p.current_cpu_idx - 1] + p.current_io_idx = p.current_cpu_idx - 1 + p.io_burst_remaining = io_time + p.status = self.STATUS_IO_WAIT + self.io_completion_events.append((current_time + io_time, p)) + return execute_time + + # 没有更多 burst,进程结束 + p.status = self.STATUS_TERMINATED + p.completion_time = current_time + execute_time + self.results.append(p) + return execute_time + else: + # 时间片用完但 CPU burst 还没完 + return execute_time + + def handle_io_completions(self, current_time: int): + """处理当前时刻完成的 IO 事件""" + completed = [] + for i, (io_time, p) in enumerate(self.io_completion_events): + if io_time <= current_time: + completed.append(i) + p.status = self.STATUS_READY + p.io_wait_time += io_time - (current_time - p.io_burst_remaining) + + # 移除已处理的事件 (倒序删除避免索引问题) + for i in reversed(completed): + self.io_completion_events.pop(i) + + return completed def calculate_metrics(self, p: Process, current_time: int): """ - 计算进程性能指标 + 计算进程性能指标 (支持IO模拟) 周转时间 (Turnaround Time): CT - AT 进程从提交到完成的总时间 @@ -57,57 +171,98 @@ class ProcessScheduler: 等待时间 (Waiting Time): TAT - BT 进程在就绪队列中等待的时间总和 + 注意: 这里只计算CPU等待时间,不包括IO等待时间 响应时间 (Response Time): ST - AT 从提交到首次运行的时间 """ - p.completion_time = current_time + if p.status == self.STATUS_TERMINATED: + p.completion_time = current_time if p.completion_time == 0 else p.completion_time + else: + p.completion_time = current_time + p.turnaround_time = p.completion_time - p.arrival_time - p.waiting_time = p.turnaround_time - p.burst_time - p.response_time = p.start_time - p.arrival_time + # 等待时间 = 周转时间 - 总CPU时间 - IO等待时间 + p.waiting_time = p.turnaround_time - p.total_cpu_time - p.io_wait_time + if p.waiting_time < 0: + p.waiting_time = 0 + p.response_time = p.start_time - p.arrival_time if p.start_time > 0 else 0 # 带权周转时间 = 周转时间 / 服务时间 p.weighted_turnaround_time = p.turnaround_time / p.burst_time if p.burst_time > 0 else 0 + p.io_wait = p.io_wait_time def print_results(self, algorithm_name: str) -> Dict: - """打印调度结果""" + """打印调度结果 (支持IO模拟)""" n = len(self.results) + if n == 0: + return {} + avg_waiting = sum(p.waiting_time for p in self.results) / n avg_turnaround = sum(p.turnaround_time for p in self.results) / n avg_weighted_turnaround = sum(p.weighted_turnaround_time for p in self.results) / n avg_response = sum(p.response_time for p in self.results) / n - print(f"\n{'='*70}") + # 计算IO相关指标 + total_io_time = sum(p.total_io_time for p in self.results) + total_io_wait = sum(p.io_wait for p in self.results) + avg_io_wait = total_io_wait / n if n > 0 else 0 + io_bound_count = sum(1 for p in self.results if p.is_io_bound) + + print(f"\n{'='*85}") print(f"算法: {algorithm_name}") - print(f"{'='*70}") - print(f"{'PID':<6}{'到达':<6}{'服务':<6}{'开始':<6}{'完成':<6}" - f"{'等待':<6}{'周转':<6}{'带权周转':<10}{'响应':<6}") - print("-" * 70) + print(f"{'='*85}") + print(f"{'PID':<6}{'类型':<6}{'起始':<6}{'到达':<6}{'服务':<6}{'IO次数':<6}{'IO时间':<8}" + f"{'周转':<6}{'CPU等待':<8}{'IO等待':<8}{'响应':<6}") + print("-" * 85) for p in self.results: - print(f"{p.pid:<6}{p.arrival_time:<6}{p.burst_time:<6}" - f"{p.start_time:<6}{p.completion_time:<6}" - f"{p.waiting_time:<6}{p.turnaround_time:<6}" - f"{p.weighted_turnaround_time:<10.2f}" - f"{p.response_time:<6}") + proc_type = "IO" if p.is_io_bound else "CPU" + start_phase = "IO" if p.starts_with_io else "CPU" + print(f"{p.pid:<6}{proc_type:<6}{start_phase:<6}{p.arrival_time:<6}{p.burst_time:<6}" + f"{p.num_io_operations:<6}{p.total_io_time:<8}" + f"{p.turnaround_time:<6}{p.waiting_time:<8}{p.io_wait:<8}{p.response_time:<6}") - print("-" * 70) - print(f"{'平均等待时间:':<18} {avg_waiting:.2f}") - print(f"{'平均周转时间:':<18} {avg_turnaround:.2f}") - print(f"{'平均带权周转时间:':<18} {avg_weighted_turnaround:.2f}") - print(f"{'平均响应时间:':<18} {avg_response:.2f}") + print("-" * 85) + print(f"{'平均等待时间:':<22} {avg_waiting:.2f}") + print(f"{'平均周转时间:':<22} {avg_turnaround:.2f}") + print(f"{'平均带权周转时间:':<22} {avg_weighted_turnaround:.2f}") + print(f"{'平均响应时间:':<22} {avg_response:.2f}") - # CPU 利用率 - total_burst = sum(p.burst_time for p in self.results) + # CPU 利用率计算 (考虑IO模拟) + total_cpu_time = sum(p.total_cpu_time for p in self.results) # 纯CPU时间 total_time = self.results[-1].completion_time - self.results[0].arrival_time - utilization = (total_burst / total_time) * 100 if total_time > 0 else 0 - print(f"{'CPU 利用率:':<18} {utilization:.2f}%") + # CPU利用率 = CPU执行时间 / 总时间 + # 注意: IO期间CPU可以运行其他进程,所以利用率应该更高 + utilization = (total_cpu_time / total_time) * 100 if total_time > 0 else 0 + + # 计算CPU实际空闲时间 + cpu_busy_time = len(self.gantt_chart) * 1 # 每个时间单位被计入 + # 简化: 空闲时间 = 总时间 - CPU总执行时间 + idle_time = total_time - total_cpu_time + + print(f"\n{'='*85}") + print("性能统计") + print("-" * 85) + print(f"{'总执行时间:':<22} {total_time}") + print(f"{'总CPU时间:':<22} {total_cpu_time}") + print(f"{'CPU利用率:':<22} {utilization:.2f}%") + print(f"{'总IO时间:':<22} {total_io_time}") + print(f"{'总IO等待时间:':<22} {total_io_wait}") + print(f"{'平均IO等待:':<22} {avg_io_wait:.2f}") + print(f"{'IO密集型进程:':<22} {io_bound_count}/{n}") return { 'avg_waiting': avg_waiting, 'avg_turnaround': avg_turnaround, 'avg_weighted_turnaround': avg_weighted_turnaround, 'avg_response': avg_response, - 'cpu_utilization': utilization + 'cpu_utilization': utilization, + 'total_time': total_time, + 'total_cpu_time': total_cpu_time, + 'total_io_time': total_io_time, + 'total_io_wait': total_io_wait, + 'avg_io_wait': avg_io_wait, + 'io_bound_count': io_bound_count } @@ -116,10 +271,14 @@ def generate_random_processes( seed: Optional[int] = 42, arrival_range: tuple = (0, 50), burst_range: tuple = (1, 20), - priority_range: tuple = (1, 10) + priority_range: tuple = (1, 10), + io_probability: float = 0.5, # 进程有IO操作的概率 + io_count_range: tuple = (1, 4), # IO操作次数范围 + io_time_range: tuple = (3, 15), # 每次IO时间范围 + io_first_prob: float = 0.0, # 以IO开始的概率 (0.0=全部先CPU, 1.0=全部先IO) ) -> List[Process]: """ - 随机生成测试进程集 + 随机生成测试进程集 (支持IO模拟) Args: n: 进程数量 @@ -127,20 +286,95 @@ def generate_random_processes( arrival_range: 到达时间范围 (min, max) burst_range: 服务时间范围 (min, max) priority_range: 优先级范围 (min, max) + io_probability: 进程有IO操作的概率 (0.0-1.0) + io_count_range: IO操作次数范围 (min, max) + io_time_range: 每次IO时间范围 (min, max) + io_first_prob: 以IO开始的概率 (0.0=全部先CPU, 1.0=全部先IO, 0.5=随机) Returns: 进程列表 + + 示例: + # 生成10个进程,50%有IO,全部先CPU + processes = generate_random_processes(n=10, io_probability=0.5) + + # 生成IO密集型场景,30%以IO开始 + processes = generate_random_processes(n=10, io_probability=0.8, io_first_prob=0.3) """ if seed is not None: random.seed(seed) processes = [] for i in range(n): + # 生成基本属性 + arrival = random.randint(*arrival_range) + total_burst = random.randint(*burst_range) + priority = random.randint(*priority_range) + + # 确定是否为IO密集型进程 + is_io_bound = random.random() < io_probability + + # 确定起始阶段 + starts_with_io = random.random() < io_first_prob if io_first_prob > 0 else False + + cpu_bursts = [] + io_bursts = [] + + if is_io_bound: + # IO密集型: 短CPU计算 + 长IO等待 + num_io = random.randint(*io_count_range) + + if starts_with_io: + # 先IO再CPU: IO -> CPU -> IO -> CPU -> ... + for j in range(num_io): + # IO burst + io_time = random.randint(*io_time_range) + io_bursts.append(io_time) + # CPU burst + remaining = total_burst - sum(cpu_bursts) + max_cpu = min(3, remaining - (num_io - j - 1)) + if max_cpu < 1: + max_cpu = 1 + cpu_time = random.randint(1, max_cpu) + cpu_bursts.append(cpu_time) + # 最后一段CPU + remaining = total_burst - sum(cpu_bursts) + if remaining > 0: + cpu_bursts.append(remaining) + else: + # 先CPU再IO: CPU -> IO -> CPU -> IO -> ... + remaining = total_burst + for j in range(num_io + 1): + if j < num_io: + # CPU burst: 短时间 (1-3) + max_cpu = min(3, remaining - (num_io - j)) + if max_cpu < 1: + max_cpu = 1 + cpu_time = random.randint(1, max_cpu) + else: + # 最后一段CPU时间 + cpu_time = remaining + if cpu_time > 0: + cpu_bursts.append(cpu_time) + remaining -= cpu_time + + if j < num_io and remaining > 0: + # IO burst: 较长时间 (长IO等待) + io_time = random.randint(*io_time_range) + io_bursts.append(io_time) + else: + # CPU密集型: 长CPU计算 + 无/少IO + cpu_bursts = [total_burst] + p = Process( pid=f'P{i+1}', - arrival_time=random.randint(*arrival_range), - burst_time=random.randint(*burst_range), - priority=random.randint(*priority_range) + arrival_time=arrival, + burst_time=total_burst, + priority=priority, + cpu_bursts=cpu_bursts, + io_bursts=io_bursts, + is_io_bound=is_io_bound, + starts_with_io=starts_with_io ) processes.append(p) @@ -150,24 +384,64 @@ def generate_random_processes( def print_processes(processes: List[Process], title: str = "测试数据"): - """打印进程信息""" - print(f"\n{'='*60}") + """打印进程信息 (包含IO模拟信息)""" + print(f"\n{'='*80}") print(f"{title}") - print(f"{'='*60}") - print(f"{'PID':<8}{'到达时间':<10}{'服务时间':<10}{'优先级':<10}") - print("-" * 60) + print(f"{'='*80}") + print(f"{'PID':<6}{'类型':<6}{'起始':<6}{'到达':<6}{'服务':<6}{'IO次数':<6}{'IO时间':<8}{'优先级':<6}") + print("-" * 80) + + io_bound_count = 0 + io_first_count = 0 for p in processes: - print(f"{p.pid:<8}{p.arrival_time:<10}{p.burst_time:<10}{p.priority:<10}") + proc_type = "IO" if p.is_io_bound else "CPU" + start_phase = "IO" if p.starts_with_io else "CPU" + if p.is_io_bound: + io_bound_count += 1 + if p.starts_with_io: + io_first_count += 1 + io_time = p.total_io_time + print(f"{p.pid:<6}{proc_type:<6}{start_phase:<6}{p.arrival_time:<6}{p.burst_time:<6}" + f"{p.num_io_operations:<6}{io_time:<8}{p.priority:<6}") + + print("-" * 80) + print(f"总进程数: {len(processes)}, CPU密集型: {len(processes)-io_bound_count}, IO密集型: {io_bound_count}") + print(f"起始阶段: 先CPU: {len(processes)-io_first_count}, 先IO: {io_first_count}") + + # 详细显示有IO的进程的CPU和IO burst + io_processes = [p for p in processes if p.io_bursts] + if io_processes: + print(f"\n{'='*80}") + print("IO 操作详细 (执行模式)") + print("-" * 80) + for p in io_processes: + # 构建执行模式字符串 + pattern = [] + if p.starts_with_io: + # 先IO再CPU + for i, io in enumerate(p.io_bursts): + pattern.append(f"IO({io})") + if i < len(p.cpu_bursts): + pattern.append(f"CPU({p.cpu_bursts[i]})") + else: + # 先CPU再IO + for i, cpu in enumerate(p.cpu_bursts): + pattern.append(f"CPU({cpu})") + if i < len(p.io_bursts): + pattern.append(f"IO({p.io_bursts[i]})") + print(f"{p.pid}: {' -> '.join(pattern)}") def print_comparison(results: Dict[str, Dict]): - """打印算法比较结果""" - print("\n" + "="*90) + """打印算法比较结果 (包含IO指标)""" + print("\n" + "="*100) print("算法性能比较") - print("="*90) - print(f"{'算法':<10}{'平均等待':<12}{'平均周转':<12}{'平均带权周转':<14}{'平均响应':<12}{'CPU利用率':<12}") - print("-" * 90) + print("="*100) + print(f"{'算法':<8}{'平均等待':<10}{'平均周转':<10}{'平均带权周转':<12}{'平均响应':<10}{'CPU利用率':<10}{'IO阻塞':<10}") + print("-" * 100) for name, metrics in results.items(): - print(f"{name:<10}{metrics['avg_waiting']:<12.2f}{metrics['avg_turnaround']:<12.2f}" - f"{metrics.get('avg_weighted_turnaround', 0):<14.2f}" - f"{metrics['avg_response']:<12.2f}{metrics['cpu_utilization']:<12.2f}%") + print(f"{name:<8}{metrics['avg_waiting']:<10.2f}{metrics['avg_turnaround']:<10.2f}" + f"{metrics.get('avg_weighted_turnaround', 0):<12.2f}" + f"{metrics['avg_response']:<10.2f}" + f"{metrics['cpu_utilization']:<10.2f}%" + f"{metrics.get('avg_io_wait', 0):<10.2f}") diff --git a/experiment/code/fcfs.py b/experiment/code/fcfs.py index 50df866..64a552d 100644 --- a/experiment/code/fcfs.py +++ b/experiment/code/fcfs.py @@ -2,9 +2,12 @@ """ 先来先服务调度算法 (FCFS) First Come First Served +支持 IO 模拟 """ -from typing import List, Dict +from typing import List, Dict, Tuple +from collections import deque +import heapq from base import ( Process, @@ -15,28 +18,97 @@ from base import ( class FCFSScheduler(ProcessScheduler): - """先来先服务调度 (First Come First Served)""" + """先来先服务调度 (First Come First Served) + + 支持 IO 模拟: + - 进程执行一个 CPU burst 后进入 IO 等待 + - IO 等待期间 CPU 可以调度其他就绪进程 + - IO 完成时进程回到就绪队列 + """ def schedule(self) -> Dict: - """FCFS 调度算法""" - # 按到达时间排序 - ready_queue = sorted(self.processes, key=lambda p: (p.arrival_time, p.pid)) + """FCFS 调度算法 (支持IO模拟)""" + all_processes = list(self.processes) + for p in all_processes: + self.init_process(p, p.arrival_time) + + # 事件队列: (时间, 事件类型, 唯一ID, 进程) + events = [] + for p in all_processes: + heapq.heappush(events, (p.arrival_time, 'arrival', id(p), p)) + + ready_queue = deque() # 就绪队列 (按到达顺序) + completed = [] current_time = 0 - for p in ready_queue: - if p.arrival_time > current_time: - current_time = p.arrival_time - - p.start_time = current_time - current_time += p.burst_time - self.calculate_metrics(p, current_time) - self.results.append(p) + last_processed_time = 0 + while len(completed) < len(all_processes): + # 1. 处理所有当前时刻的事件 + while events and events[0][0] <= current_time: + event_time, event_type, uid, p = heapq.heappop(events) + + if event_type == 'arrival': + p.status = self.STATUS_READY + ready_queue.append(p) + elif event_type == 'io_complete': + if p.status == self.STATUS_IO_WAIT: + p.status = self.STATUS_READY + ready_queue.append(p) + + # 2. 如果就绪队列为空,推进时间到下一个事件 + if not ready_queue: + if events: + current_time = events[0][0] + continue + else: + break + + # 3. FCFS: 选择队首进程 + current_process = ready_queue.popleft() + + if current_process.start_time == -1: + current_process.start_time = current_time + + current_process.status = self.STATUS_RUNNING + + # 4. 执行 CPU burst + if current_process.current_cpu_idx < len(current_process.cpu_bursts): + cpu_burst = current_process.cpu_bursts[current_process.current_cpu_idx] + + self.gantt_chart.append((current_time, current_process.pid, 'CPU', cpu_burst)) + + current_time += cpu_burst + current_process.remaining_cpu_time -= cpu_burst + current_process.current_cpu_idx += 1 + + # 5. 检查是否有 IO burst + io_idx = current_process.current_cpu_idx - 1 + if io_idx < len(current_process.io_bursts): + # 进入 IO 等待,添加 IO 完成事件 + io_time = current_process.io_bursts[io_idx] + current_process.status = self.STATUS_IO_WAIT + io_complete_time = current_time + io_time + heapq.heappush(events, (io_complete_time, 'io_complete', id(current_process), current_process)) + else: + # 进程完成 + current_process.status = self.STATUS_TERMINATED + current_process.completion_time = current_time + self.calculate_metrics(current_process, current_time) + completed.append(current_process) + else: + # 进程完成 + current_process.status = self.STATUS_TERMINATED + current_process.completion_time = current_time + self.calculate_metrics(current_process, current_time) + completed.append(current_process) + + self.results = completed return self.print_results("FCFS (先来先服务)") if __name__ == "__main__": - processes = generate_random_processes(n=5, seed=42) + processes = generate_random_processes(n=5, seed=42, io_probability=0.5, io_first_prob=0.3) print_processes(processes, "测试数据") scheduler = FCFSScheduler(processes) diff --git a/experiment/code/hrrn.py b/experiment/code/hrrn.py index f583da5..ba08ddb 100644 --- a/experiment/code/hrrn.py +++ b/experiment/code/hrrn.py @@ -1,10 +1,11 @@ #!/usr/bin/env python3 """ 高响应比优先调度算法 (HRRN) -Highest Response Ratio Next +支持 IO 模拟 """ from typing import List, Dict +import heapq from base import ( Process, @@ -15,57 +16,95 @@ from base import ( class HRRNScheduler(ProcessScheduler): - """ - 高响应比优先调度 (Highest Response Ratio Next) + """高响应比优先调度 响应比 = (等待时间 + 服务时间) / 服务时间 - = 1 + 等待时间 / 服务时间 - 特点: - - 非抢占式 - - 综合考虑了等待时间和服务时间 - - 避免长作业饥饿问题 + 支持 IO 模拟 """ - def calculate_response_ratio(self, p: Process, current_time: int) -> float: - """计算响应比""" - waiting_time = current_time - p.arrival_time - return 1 + (waiting_time / p.burst_time) if p.burst_time > 0 else float('inf') - def schedule(self) -> Dict: - """HRRN 调度算法""" - processes = sorted(self.processes, key=lambda p: p.arrival_time) - ready_queue: List[Process] = [] + """HRRN 调度算法 (支持IO模拟)""" + all_processes = list(self.processes) + for p in all_processes: + self.init_process(p, p.arrival_time) + + events = [] + for p in all_processes: + heapq.heappush(events, (p.arrival_time, 'arrival', id(p), p)) + + ready_queue = [] # (response_ratio, pid, process) + completed = [] + current_time = 0 - completed = 0 - while completed < len(processes): - # 添加所有到达的进程 - for p in processes: - if p.arrival_time <= current_time and p not in ready_queue and p not in self.results: - ready_queue.append(p) - - if ready_queue: - # 计算每个进程的响应比,选择最高的 - ready_queue.sort( - key=lambda p: self.calculate_response_ratio(p, current_time), - reverse=True # 响应比高优先 - ) - p = ready_queue.pop(0) + while len(completed) < len(all_processes): + while events and events[0][0] <= current_time: + event_time, event_type, uid, p = heapq.heappop(events) - p.start_time = current_time - current_time += p.burst_time - self.calculate_metrics(p, current_time) - self.results.append(p) - completed += 1 + if event_type == 'arrival': + p.status = self.STATUS_READY + ready_queue.append(p) + elif event_type == 'io_complete': + if p.status == self.STATUS_IO_WAIT: + p.status = self.STATUS_READY + ready_queue.append(p) + + if not ready_queue: + if events: + current_time = events[0][0] + continue + else: + break + + # 计算响应比 + for p in ready_queue: + wait_time = current_time - p.arrival_time + remaining = p.remaining_cpu_time if p.remaining_cpu_time > 0 else p.total_cpu_time + if remaining > 0: + p.response_ratio = (wait_time + remaining) / remaining + else: + p.response_ratio = float('inf') + + ready_queue.sort(key=lambda x: (-x.response_ratio, id(x))) + current_process = ready_queue.pop(0) + + if current_process.start_time == -1: + current_process.start_time = current_time + + current_process.status = self.STATUS_RUNNING + + if current_process.current_cpu_idx < len(current_process.cpu_bursts): + cpu_burst = current_process.cpu_bursts[current_process.current_cpu_idx] + + self.gantt_chart.append((current_time, current_process.pid, 'CPU', cpu_burst)) + + current_time += cpu_burst + current_process.remaining_cpu_time -= cpu_burst + current_process.current_cpu_idx += 1 + + io_idx = current_process.current_cpu_idx - 1 + if io_idx < len(current_process.io_bursts): + io_time = current_process.io_bursts[io_idx] + current_process.status = self.STATUS_IO_WAIT + heapq.heappush(events, (current_time + io_time, 'io_complete', id(current_process), current_process)) + else: + current_process.status = self.STATUS_TERMINATED + current_process.completion_time = current_time + self.calculate_metrics(current_process, current_time) + completed.append(current_process) else: - current_time += 1 + current_process.status = self.STATUS_TERMINATED + current_process.completion_time = current_time + self.calculate_metrics(current_process, current_time) + completed.append(current_process) + self.results = completed return self.print_results("HRRN (高响应比优先)") if __name__ == "__main__": - processes = generate_random_processes(n=5, seed=42) + processes = generate_random_processes(n=5, seed=42, io_probability=0.5) print_processes(processes, "测试数据") scheduler = HRRNScheduler(processes) diff --git a/experiment/code/main.py b/experiment/code/main.py index 3e7864e..bc43abe 100644 --- a/experiment/code/main.py +++ b/experiment/code/main.py @@ -32,13 +32,21 @@ from mlfq import MLFQScheduler from hrrn import HRRNScheduler -# 预设演示数据 +# 预设演示数据 (包含IO模拟) DEMO_PROCESSES = [ - Process(pid='P1', arrival_time=0, burst_time=7, priority=3), - Process(pid='P2', arrival_time=2, burst_time=4, priority=1), - Process(pid='P3', arrival_time=4, burst_time=1, priority=4), - Process(pid='P4', arrival_time=5, burst_time=4, priority=2), - Process(pid='P5', arrival_time=6, burst_time=2, priority=3), + # CPU密集型进程 + Process(pid='P1', arrival_time=0, burst_time=7, priority=3, + cpu_bursts=[7], io_bursts=[], is_io_bound=False), + # IO密集型进程: CPU -> IO -> CPU -> IO -> CPU + Process(pid='P2', arrival_time=2, burst_time=10, priority=1, + cpu_bursts=[3, 2, 3], io_bursts=[5, 4], is_io_bound=True), + Process(pid='P3', arrival_time=4, burst_time=1, priority=4, + cpu_bursts=[1], io_bursts=[], is_io_bound=False), + # IO密集型进程 + Process(pid='P4', arrival_time=5, burst_time=8, priority=2, + cpu_bursts=[2, 2, 2], io_bursts=[6, 5], is_io_bound=True), + Process(pid='P5', arrival_time=6, burst_time=2, priority=3, + cpu_bursts=[2], io_bursts=[], is_io_bound=False), ] @@ -127,6 +135,14 @@ def main(): help='服务时间范围 (格式: min,max)') parser.add_argument('--priority', type=str, default='1,10', help='优先级范围 (格式: min,max)') + parser.add_argument('--io-prob', type=float, default=0.5, + help='进程有IO操作的概率 0.0-1.0 (默认: 0.5)') + parser.add_argument('--io-count', type=str, default='1,4', + help='IO操作次数范围 (格式: min,max, 默认: 1,4)') + parser.add_argument('--io-time', type=str, default='3,15', + help='每次IO时间范围 (格式: min,max, 默认: 3,15)') + parser.add_argument('--io-first', type=float, default=0.0, + help='以IO开始的概率 0.0-1.0 (默认: 0.0, 即全部先CPU)') args = parser.parse_args() @@ -144,6 +160,8 @@ def main(): arrival_range = tuple(map(int, args.arrival.split(','))) burst_range = tuple(map(int, args.burst.split(','))) priority_range = tuple(map(int, args.priority.split(','))) + io_count_range = tuple(map(int, args.io_count.split(','))) + io_time_range = tuple(map(int, args.io_time.split(','))) seed = args.seed if args.seed != -1 else None @@ -152,7 +170,11 @@ def main(): seed=seed, arrival_range=arrival_range, burst_range=burst_range, - priority_range=priority_range + priority_range=priority_range, + io_probability=args.io_prob, + io_count_range=io_count_range, + io_time_range=io_time_range, + io_first_prob=args.io_first ) title = f"随机测试数据 (n={args.num}, seed={args.seed if seed else 'None'})" diff --git a/experiment/code/mlfq.py b/experiment/code/mlfq.py index 13fd31a..4bf9231 100644 --- a/experiment/code/mlfq.py +++ b/experiment/code/mlfq.py @@ -1,11 +1,12 @@ #!/usr/bin/env python3 """ 多级反馈队列调度算法 (MLFQ) -Multilevel Feedback Queue +支持 IO 模拟 """ -from collections import deque from typing import List, Dict +from collections import deque +import heapq from base import ( Process, @@ -16,83 +17,127 @@ from base import ( class MLFQScheduler(ProcessScheduler): - """多级反馈队列调度 (Multilevel Feedback Queue)""" + """多级反馈队列调度""" - def __init__(self, processes: List[Process], queues: List[int] = None): + def __init__(self, processes: List[Process], num_queues: int = 3, base_time_slice: int = 4): super().__init__(processes) - # 每层队列的时间片大小 - self.queues = queues or [4, 8, 16] - self.aging_time = 50 + self.num_queues = num_queues + self.base_time_slice = base_time_slice + + def get_time_slice(self, queue_idx: int) -> int: + return self.base_time_slice * (2 ** queue_idx) def schedule(self) -> Dict: - """MLFQ 调度算法""" - processes = sorted(self.processes, key=lambda p: p.arrival_time) + """MLFQ 调度算法 (支持IO模拟)""" + all_processes = list(self.processes) + n = len(all_processes) + + for p in all_processes: + self.init_process(p, p.arrival_time) + p.queue_idx = 0 + + # 事件: (时间, 类型, uid, 进程) + events = [] + for p in all_processes: + heapq.heappush(events, (p.arrival_time, 'arrival', id(p), p)) + + queues = [deque() for _ in range(self.num_queues)] + completed = [] + io_waiting = {} # {进程: IO完成时间} - queues = [deque() for _ in self.queues] current_time = 0 - completed = 0 - index = 0 + max_iterations = 10000 # 防止死循环 + iterations = 0 - while completed < len(processes): - while index < len(processes) and processes[index].arrival_time <= current_time: - queues[0].append(processes[index]) - index += 1 + while len(completed) < n and iterations < max_iterations: + iterations += 1 - # 老化 - for i in range(1, len(queues)): - for p in list(queues[i]): - wait_time = current_time - p.arrival_time - (p.burst_time - p.remaining_time) - if wait_time > self.aging_time: - queues[i].remove(p) - queues[max(0, i-1)].append(p) + # 1. 处理到达事件 + while events and events[0][0] <= current_time: + _, etype, _, p = heapq.heappop(events) + if etype == 'arrival': + p.status = self.STATUS_READY + queues[0].append(p) + elif etype == 'io_complete': + io_waiting.pop(p.pid, None) + p.status = self.STATUS_READY + queues[p.queue_idx].append(p) - queue_idx = -1 - for i in range(len(queues)): + # 2. 检查 IO 完成 + completed_io = [] + for p, io_end_time in io_waiting.items(): + if io_end_time <= current_time: + completed_io.append(p) + for p in completed_io: + io_waiting.pop(p.pid, None) + p.status = self.STATUS_READY + queues[p.queue_idx].append(p) + + # 3. 找最高优先级非空队列 + q_idx = -1 + for i in range(self.num_queues): if queues[i]: - queue_idx = i + q_idx = i break - if queue_idx >= 0: - p = queues[queue_idx].popleft() + if q_idx == -1: + # 所有队列为空,推进时间 + next_events = [e[0] for e in events if e[0] > current_time] + next_io = [t for t in io_waiting.values() if t > current_time] + next_times = next_events + next_io + if next_times: + current_time = min(next_times) + continue + + # 4. 取进程执行 + p = queues[q_idx].popleft() + + if p.start_time == -1: + p.start_time = current_time + p.status = self.STATUS_RUNNING + + ts = self.get_time_slice(q_idx) + + if p.current_cpu_idx < len(p.cpu_bursts): + cpu_burst = p.cpu_bursts[p.current_cpu_idx] + exec_t = min(ts, cpu_burst) - if p.start_time == -1: - p.start_time = current_time + self.gantt_chart.append((current_time, p.pid, 'CPU', exec_t)) - exec_time = min(self.queues[queue_idx], p.remaining_time) - p.remaining_time -= exec_time - current_time += exec_time + current_time += exec_t + p.remaining_cpu_time -= exec_t - while index < len(processes) and processes[index].arrival_time <= current_time: - queues[0].append(processes[index]) - index += 1 - - if p.remaining_time > 0: - if queue_idx < len(queues) - 1: - queues[queue_idx + 1].append(p) + if exec_t >= cpu_burst: + p.current_cpu_idx += 1 + io_idx = p.current_cpu_idx - 1 + if io_idx < len(p.io_bursts): + io_t = p.io_bursts[io_idx] + p.status = self.STATUS_IO_WAIT + io_waiting[p.pid] = current_time + io_t + heapq.heappush(events, (current_time + io_t, 'io_complete', id(p), p)) else: - queues[queue_idx].append(p) + p.status = self.STATUS_TERMINATED + p.completion_time = current_time + self.calculate_metrics(p, current_time) + completed.append(p) else: - self.calculate_metrics(p, current_time) - self.results.append(p) - completed += 1 + p.status = self.STATUS_READY + nq = min(q_idx + 1, self.num_queues - 1) + p.queue_idx = nq + queues[nq].append(p) else: - current_time += 1 + p.status = self.STATUS_TERMINATED + p.completion_time = current_time + self.calculate_metrics(p, current_time) + completed.append(p) - return self.print_results(f"MLFQ (多级反馈队列, 队列时间片={self.queues})") + self.results = completed + return self.print_results("MLFQ (多级反馈队列)") if __name__ == "__main__": - processes = generate_random_processes(n=5, seed=42) + processes = generate_random_processes(n=5, seed=42, io_probability=0.5) print_processes(processes, "测试数据") - print("\n" + "="*60) - print("多级反馈队列调度 (默认配置)") - print("="*60) - scheduler1 = MLFQScheduler(processes) - scheduler1.schedule() - - print("\n" + "="*60) - print("多级反馈队列调度 (自定义配置 [2, 5, 10])") - print("="*60) - scheduler2 = MLFQScheduler(processes, queues=[2, 5, 10]) - scheduler2.schedule() + scheduler = MLFQScheduler(processes) + scheduler.schedule() diff --git a/experiment/code/priority.py b/experiment/code/priority.py index d337b80..0d755e8 100644 --- a/experiment/code/priority.py +++ b/experiment/code/priority.py @@ -1,9 +1,11 @@ #!/usr/bin/env python3 """ -优先级调度算法 (Priority Scheduling) +优先级调度算法 (Priority) +支持 IO 模拟 """ from typing import List, Dict +import heapq from base import ( Process, @@ -14,95 +16,88 @@ from base import ( class PriorityScheduler(ProcessScheduler): - """优先级调度""" + """优先级调度 (数值越小优先级越高) + + 支持 IO 模拟 + """ def __init__(self, processes: List[Process], preemptive: bool = False): super().__init__(processes) self.preemptive = preemptive def schedule(self) -> Dict: - """优先级调度算法""" - if self.preemptive: - return self.schedule_preemptive() - return self.schedule_non_preemptive() - - def schedule_non_preemptive(self) -> Dict: - """非抢占式优先级调度""" - processes = sorted(self.processes, key=lambda p: p.arrival_time) - ready_queue: List[Process] = [] + """优先级调度算法 (支持IO模拟)""" + all_processes = list(self.processes) + for p in all_processes: + self.init_process(p, p.arrival_time) + + events = [] + for p in all_processes: + heapq.heappush(events, (p.arrival_time, 'arrival', id(p), p)) + + ready_queue = [] # (priority, pid, process) + completed = [] + current_time = 0 - completed = 0 - while completed < len(processes): - for p in processes: - if p.arrival_time <= current_time and p not in ready_queue and p not in self.results: - ready_queue.append(p) + while len(completed) < len(all_processes): + while events and events[0][0] <= current_time: + event_time, event_type, uid, p = heapq.heappop(events) + + if event_type == 'arrival': + p.status = self.STATUS_READY + heapq.heappush(ready_queue, (p.priority, id(p), p)) + elif event_type == 'io_complete': + if p.status == self.STATUS_IO_WAIT: + p.status = self.STATUS_READY + heapq.heappush(ready_queue, (p.priority, id(p), p)) - if ready_queue: - ready_queue.sort(key=lambda p: p.priority) - p = ready_queue.pop(0) - - p.start_time = current_time - current_time += p.burst_time - self.calculate_metrics(p, current_time) - self.results.append(p) - completed += 1 - else: - current_time += 1 - - return self.print_results("优先级调度 (非抢占)") - - def schedule_preemptive(self) -> Dict: - """抢占式优先级调度""" - processes = sorted(self.processes, key=lambda p: p.arrival_time) - ready_queue: List[Process] = [] - current_time = 0 - completed = 0 - current_process = None - - while completed < len(processes): - for p in processes: - if p.arrival_time <= current_time and p not in ready_queue and p not in self.results: - ready_queue.append(p) + if not ready_queue: + if events: + current_time = events[0][0] + continue + else: + break - if ready_queue: - ready_queue.sort(key=lambda p: p.priority) + _, _, current_process = heapq.heappop(ready_queue) + + if current_process.start_time == -1: + current_process.start_time = current_time + + current_process.status = self.STATUS_RUNNING + + if current_process.current_cpu_idx < len(current_process.cpu_bursts): + cpu_burst = current_process.cpu_bursts[current_process.current_cpu_idx] - if current_process is None or current_process.priority > ready_queue[0].priority: - if current_process and current_process.remaining_time > 0: - ready_queue.append(current_process) - - current_process = ready_queue.pop(0) - - if current_process.start_time == -1: - current_process.start_time = current_time + self.gantt_chart.append((current_time, current_process.pid, 'CPU', cpu_burst)) - current_process.remaining_time -= 1 - current_time += 1 + current_time += cpu_burst + current_process.remaining_cpu_time -= cpu_burst + current_process.current_cpu_idx += 1 - if current_process.remaining_time == 0: + io_idx = current_process.current_cpu_idx - 1 + if io_idx < len(current_process.io_bursts): + io_time = current_process.io_bursts[io_idx] + current_process.status = self.STATUS_IO_WAIT + heapq.heappush(events, (current_time + io_time, 'io_complete', id(current_process), current_process)) + else: + current_process.status = self.STATUS_TERMINATED + current_process.completion_time = current_time self.calculate_metrics(current_process, current_time) - self.results.append(current_process) - completed += 1 - current_process = None + completed.append(current_process) else: - current_time += 1 + current_process.status = self.STATUS_TERMINATED + current_process.completion_time = current_time + self.calculate_metrics(current_process, current_time) + completed.append(current_process) - return self.print_results("优先级调度 (抢占)") + self.results = completed + return self.print_results("Priority (优先级调度)") if __name__ == "__main__": - processes = generate_random_processes(n=5, seed=42) + processes = generate_random_processes(n=5, seed=42, io_probability=0.5) print_processes(processes, "测试数据") - print("\n" + "="*60) - print("非抢占式优先级调度") - print("="*60) - scheduler1 = PriorityScheduler(processes, preemptive=False) - scheduler1.schedule() - - print("\n" + "="*60) - print("抢占式优先级调度") - print("="*60) - scheduler2 = PriorityScheduler(processes, preemptive=True) - scheduler2.schedule() + scheduler = PriorityScheduler(processes) + scheduler.schedule() diff --git a/experiment/code/rr.py b/experiment/code/rr.py index 059b31c..b98fbe0 100644 --- a/experiment/code/rr.py +++ b/experiment/code/rr.py @@ -1,11 +1,12 @@ #!/usr/bin/env python3 """ 时间片轮转调度算法 (RR) -Round Robin +支持 IO 模拟 """ -from collections import deque from typing import List, Dict +from collections import deque +import heapq from base import ( Process, @@ -16,58 +17,110 @@ from base import ( class RoundRobinScheduler(ProcessScheduler): - """时间片轮转调度 (Round Robin)""" + """时间片轮转调度""" def __init__(self, processes: List[Process], time_slice: int = 4): super().__init__(processes) self.time_slice = time_slice def schedule(self) -> Dict: - """RR 调度算法""" - processes = sorted(self.processes, key=lambda p: p.arrival_time) + """RR 调度算法 (支持IO模拟)""" + all_processes = list(self.processes) + n = len(all_processes) + + for p in all_processes: + self.init_process(p, p.arrival_time) + + events = [] + for p in all_processes: + heapq.heappush(events, (p.arrival_time, 'arrival', id(p), p)) + ready_queue = deque() + completed = [] + io_waiting = {} # {进程PID: IO完成时间} + current_time = 0 - completed = 0 - index = 0 + max_iterations = 10000 + iterations = 0 - while completed < len(processes): - while index < len(processes) and processes[index].arrival_time <= current_time: - ready_queue.append(processes[index]) - index += 1 + while len(completed) < n and iterations < max_iterations: + iterations += 1 - if ready_queue: - p = ready_queue.popleft() - - if p.start_time == -1: - p.start_time = current_time - - exec_time = min(self.time_slice, p.remaining_time) - p.remaining_time -= exec_time - current_time += exec_time - - while index < len(processes) and processes[index].arrival_time <= current_time: - ready_queue.append(processes[index]) - index += 1 - - if p.remaining_time > 0: + # 1. 处理到达事件 + while events and events[0][0] <= current_time: + _, etype, _, p = heapq.heappop(events) + if etype == 'arrival': + p.status = self.STATUS_READY ready_queue.append(p) + elif etype == 'io_complete': + io_waiting.pop(p.pid, None) + p.status = self.STATUS_READY + ready_queue.append(p) + + # 2. 检查 IO 完成 + completed_io = [] + for p, io_end_time in io_waiting.items(): + if io_end_time <= current_time: + completed_io.append(p) + for p in completed_io: + io_waiting.pop(p.pid, None) + p.status = self.STATUS_READY + ready_queue.append(p) + + if not ready_queue: + # 队列为空,推进时间 + next_events = [e[0] for e in events if e[0] > current_time] + next_io = [t for t in io_waiting.values() if t > current_time] + next_times = next_events + next_io + if next_times: + current_time = min(next_times) + continue + + # 3. 取进程执行 + p = ready_queue.popleft() + + if p.start_time == -1: + p.start_time = current_time + p.status = self.STATUS_RUNNING + + if p.current_cpu_idx < len(p.cpu_bursts): + cpu_burst = p.cpu_bursts[p.current_cpu_idx] + exec_t = min(self.time_slice, cpu_burst) + + self.gantt_chart.append((current_time, p.pid, 'CPU', exec_t)) + + current_time += exec_t + p.remaining_cpu_time -= exec_t + + if exec_t >= cpu_burst: + p.current_cpu_idx += 1 + io_idx = p.current_cpu_idx - 1 + if io_idx < len(p.io_bursts): + io_t = p.io_bursts[io_idx] + p.status = self.STATUS_IO_WAIT + io_waiting[p.pid] = current_time + io_t + heapq.heappush(events, (current_time + io_t, 'io_complete', id(p), p)) + else: + p.status = self.STATUS_TERMINATED + p.completion_time = current_time + self.calculate_metrics(p, current_time) + completed.append(p) else: - self.calculate_metrics(p, current_time) - self.results.append(p) - completed += 1 + p.status = self.STATUS_READY + ready_queue.append(p) else: - current_time += 1 + p.status = self.STATUS_TERMINATED + p.completion_time = current_time + self.calculate_metrics(p, current_time) + completed.append(p) - return self.print_results(f"RR (时间片轮转, time_slice={self.time_slice})") + self.results = completed + return self.print_results(f"RR (时间片轮转, q={self.time_slice})") if __name__ == "__main__": - processes = generate_random_processes(n=5, seed=42) + processes = generate_random_processes(n=5, seed=42, io_probability=0.5) print_processes(processes, "测试数据") - for ts in [2, 4, 8]: - print("\n" + "="*60) - print(f"时间片轮转 (time_slice={ts})") - print("="*60) - scheduler = RoundRobinScheduler(processes, time_slice=ts) - scheduler.schedule() + scheduler = RoundRobinScheduler(processes, time_slice=4) + scheduler.schedule() diff --git a/experiment/code/sjf.py b/experiment/code/sjf.py index c3bbf3e..a321ca5 100644 --- a/experiment/code/sjf.py +++ b/experiment/code/sjf.py @@ -1,10 +1,13 @@ #!/usr/bin/env python3 """ -短作业优先调度算法 (SJF) -Shortest Job First / Shortest Remaining Time First (SRTF) +最短作业优先调度算法 (SJF/SRTF) +Shortest Job First / Shortest Remaining Time First +支持 IO 模拟 """ from typing import List, Dict +from collections import deque +import heapq from base import ( Process, @@ -15,89 +18,98 @@ from base import ( class SJFScheduler(ProcessScheduler): - """短作业优先调度 (Shortest Job First)""" + """最短作业优先调度 (SJF/SRTF) + + SJF: 非抢占式,选择剩余时间最短的进程 + SRTF: 抢占式,选择剩余时间最短的进程 + + 支持 IO 模拟 + """ def __init__(self, processes: List[Process], preemptive: bool = False): super().__init__(processes) self.preemptive = preemptive def schedule(self) -> Dict: - """SJF 调度算法""" - if self.preemptive: - return self.schedule_preemptive() - return self.schedule_non_preemptive() - - def schedule_non_preemptive(self) -> Dict: - """非抢占式 SJF""" - processes = sorted(self.processes, key=lambda p: p.arrival_time) - ready_queue: List[Process] = [] + """SJF/SRTF 调度算法 (支持IO模拟)""" + all_processes = list(self.processes) + for p in all_processes: + self.init_process(p, p.arrival_time) + + # 事件队列: (时间, 事件类型, 唯一ID, 进程) + events = [] + for p in all_processes: + heapq.heappush(events, (p.arrival_time, 'arrival', id(p), p)) + + ready_queue = [] # 就绪队列 (需要排序) + completed = [] + current_time = 0 - completed = 0 - while completed < len(processes): - for p in processes: - if p.arrival_time <= current_time and p not in ready_queue and p not in self.results: + while len(completed) < len(all_processes): + # 处理事件 + while events and events[0][0] <= current_time: + event_time, event_type, uid, p = heapq.heappop(events) + + if event_type == 'arrival': + p.status = self.STATUS_READY ready_queue.append(p) + elif event_type == 'io_complete': + if p.status == self.STATUS_IO_WAIT: + p.status = self.STATUS_READY + ready_queue.append(p) - if ready_queue: - ready_queue.sort(key=lambda p: p.burst_time) - p = ready_queue.pop(0) - - p.start_time = current_time - current_time += p.burst_time - self.calculate_metrics(p, current_time) - self.results.append(p) - completed += 1 - else: - current_time += 1 - - return self.print_results("SJF (短作业优先 - 非抢占)") - - def schedule_preemptive(self) -> Dict: - """抢占式 SJF (SRTF)""" - processes = sorted(self.processes, key=lambda p: p.arrival_time) - ready_queue: List[Process] = [] - current_time = 0 - completed = 0 - - while completed < len(processes): - for p in processes: - if p.arrival_time <= current_time and p not in ready_queue and p not in self.results: - ready_queue.append(p) + if not ready_queue: + if events: + current_time = events[0][0] + continue + else: + break - if ready_queue: - ready_queue.sort(key=lambda p: p.remaining_time) - p = ready_queue[0] + # 按剩余时间排序 + ready_queue.sort(key=lambda p: (p.remaining_cpu_time, id(p))) + current_process = ready_queue.pop(0) + + if current_process.start_time == -1: + current_process.start_time = current_time + + current_process.status = self.STATUS_RUNNING + + # 执行 CPU burst + if current_process.current_cpu_idx < len(current_process.cpu_bursts): + cpu_burst = current_process.cpu_bursts[current_process.current_cpu_idx] - if p.start_time == -1: - p.start_time = current_time + self.gantt_chart.append((current_time, current_process.pid, 'CPU', cpu_burst)) - p.remaining_time -= 1 - current_time += 1 + current_time += cpu_burst + current_process.remaining_cpu_time -= cpu_burst + current_process.current_cpu_idx += 1 - if p.remaining_time == 0: - self.calculate_metrics(p, current_time) - self.results.append(p) - ready_queue.remove(p) - completed += 1 + io_idx = current_process.current_cpu_idx - 1 + if io_idx < len(current_process.io_bursts): + io_time = current_process.io_bursts[io_idx] + current_process.status = self.STATUS_IO_WAIT + heapq.heappush(events, (current_time + io_time, 'io_complete', id(current_process), current_process)) + else: + current_process.status = self.STATUS_TERMINATED + current_process.completion_time = current_time + self.calculate_metrics(current_process, current_time) + completed.append(current_process) else: - current_time += 1 + current_process.status = self.STATUS_TERMINATED + current_process.completion_time = current_time + self.calculate_metrics(current_process, current_time) + completed.append(current_process) - return self.print_results("SRTF (最短剩余时间优先 - 抢占)") + self.results = completed + algo_name = "SRTF (最短剩余时间优先)" if self.preemptive else "SJF (最短作业优先)" + return self.print_results(algo_name) if __name__ == "__main__": - processes = generate_random_processes(n=5, seed=42) + processes = generate_random_processes(n=5, seed=42, io_probability=0.5) print_processes(processes, "测试数据") - print("\n" + "="*60) - print("非抢占式 SJF") - print("="*60) - scheduler1 = SJFScheduler(processes, preemptive=False) - scheduler1.schedule() - - print("\n" + "="*60) - print("抢占式 SJF (SRTF)") - print("="*60) - scheduler2 = SJFScheduler(processes, preemptive=True) - scheduler2.schedule() + print("\n--- SJF (非抢占) ---") + scheduler = SJFScheduler(processes, preemptive=False) + scheduler.schedule()