From 4897bef9a68550e8229a7f79e5c86e33403321e8 Mon Sep 17 00:00:00 2001 From: ViperEkura <3081035982@qq.com> Date: Mon, 4 May 2026 23:17:42 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=BF=9B=E7=A8=8B?= =?UTF-8?q?=E8=B0=83=E5=BA=A6=E6=A8=A1=E6=8B=9F=E5=99=A8=E7=9A=84CPU?= =?UTF-8?q?=E5=88=A9=E7=94=A8=E7=8E=87=E8=AE=A1=E7=AE=97=E5=92=8C=E6=B7=B1?= =?UTF-8?q?=E6=8B=B7=E8=B4=9D=E7=AD=89bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - base.py: CPU利用率改用 min(arrival)/max(completion),total_cpu_time改用 burst_time - main.py: 深拷贝改用 copy.deepcopy 隔离列表引用,帮助文本默认值修正,演示数据 burst_time 对齐 - sjf.py: 实现 SRTF 抢占模式(逐时间单位执行) - priority.py: 实现抢占式优先级调度 - rr.py/mlfq.py: 时间片用完回写 cpu_bursts[idx],io_waiting 字典改用 pid 作 key --- experiment/code/base.py | 6 ++- experiment/code/main.py | 18 ++++---- experiment/code/mlfq.py | 20 ++++---- experiment/code/priority.py | 92 +++++++++++++++++++++++++++---------- experiment/code/rr.py | 21 +++++---- experiment/code/sjf.py | 92 ++++++++++++++++++++++++++----------- 6 files changed, 173 insertions(+), 76 deletions(-) diff --git a/experiment/code/base.py b/experiment/code/base.py index 653cbc6..f1fd6fe 100644 --- a/experiment/code/base.py +++ b/experiment/code/base.py @@ -54,7 +54,7 @@ class Process: @property def total_cpu_time(self) -> int: """总CPU计算时间""" - return sum(self.cpu_bursts) if self.cpu_bursts else self.burst_time + return self.burst_time @property def total_io_time(self) -> int: @@ -230,7 +230,9 @@ class ProcessScheduler: # 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 + first_arrival = min(p.arrival_time for p in self.results) + last_completion = max(p.completion_time for p in self.results) + total_time = last_completion - first_arrival # CPU利用率 = CPU执行时间 / 总时间 # 注意: IO期间CPU可以运行其他进程,所以利用率应该更高 utilization = (total_cpu_time / total_time) * 100 if total_time > 0 else 0 diff --git a/experiment/code/main.py b/experiment/code/main.py index bc43abe..a1c2529 100644 --- a/experiment/code/main.py +++ b/experiment/code/main.py @@ -10,13 +10,14 @@ python main.py --demo # 使用默认演示数据 参数说明: - -n, --num: 进程数量 (默认 5) + -n, --num: 进程数量 (默认 10) -s, --seed: 随机种子 (默认 42, 设为 None 则随机) -a, --algo: 运行的算法 (默认全部) --demo: 使用预设演示数据 """ import argparse +import copy from typing import List, Dict, Optional from base import ( Process, ProcessScheduler, @@ -38,12 +39,12 @@ DEMO_PROCESSES = [ 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, + Process(pid='P2', arrival_time=2, burst_time=8, 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, + Process(pid='P4', arrival_time=5, burst_time=6, 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), @@ -57,6 +58,7 @@ def get_algorithm_config() -> Dict: 'SJF': lambda p: SJFScheduler(p, preemptive=False), 'SRTF': lambda p: SJFScheduler(p, preemptive=True), 'Priority': lambda p: PriorityScheduler(p, preemptive=False), + 'PriorityP': lambda p: PriorityScheduler(p, preemptive=True), 'RR': lambda p: RoundRobinScheduler(p, time_slice=4), 'MLFQ': lambda p: MLFQScheduler(p), 'HRRN': HRRNScheduler, @@ -65,8 +67,8 @@ def get_algorithm_config() -> Dict: def run_all_algorithms(processes: List[Process], algorithms: Optional[List[str]] = None): """运行所有/指定调度算法并比较""" - # 深拷贝进程列表 - original_processes = [Process(**p.__dict__) for p in processes] + # 深拷贝进程列表 (使用 copy.deepcopy 确保 cpu_bursts/io_bursts 等列表字段独立) + original_processes = [copy.deepcopy(p) for p in processes] # 默认运行所有算法 if algorithms is None: @@ -80,8 +82,8 @@ def run_all_algorithms(processes: List[Process], algorithms: Optional[List[str]] print(f"警告: 未知算法 '{algo_name}', 跳过") continue - # 每次重新创建进程列表 - process_list = [Process(**p.__dict__) for p in original_processes] + # 每次重新创建进程列表 (深拷贝确保各算法互不影响) + process_list = [copy.deepcopy(p) for p in original_processes] # 获取调度器 scheduler_class = scheduler_map[algo_name] @@ -122,7 +124,7 @@ def main(): ) parser.add_argument('-n', '--num', type=int, default=10, - help='随机生成的进程数量 (默认: 5)') + help='随机生成的进程数量 (默认: 10)') parser.add_argument('-s', '--seed', type=int, default=42, help='随机种子 (默认: 42, 设为 None 则每次不同)') parser.add_argument('-a', '--algo', type=str, default=None, diff --git a/experiment/code/mlfq.py b/experiment/code/mlfq.py index 4bf9231..61abd24 100644 --- a/experiment/code/mlfq.py +++ b/experiment/code/mlfq.py @@ -43,7 +43,8 @@ class MLFQScheduler(ProcessScheduler): queues = [deque() for _ in range(self.num_queues)] completed = [] - io_waiting = {} # {进程: IO完成时间} + io_waiting = {} # {pid: IO完成时间} + process_map = {p.pid: p for p in all_processes} # pid -> Process 映射 current_time = 0 max_iterations = 10000 # 防止死循环 @@ -63,15 +64,16 @@ class MLFQScheduler(ProcessScheduler): p.status = self.STATUS_READY queues[p.queue_idx].append(p) - # 2. 检查 IO 完成 + # 2. 检查 IO 完成 (兜底,防止事件队列遗漏) completed_io = [] - for p, io_end_time in io_waiting.items(): + for pid, io_end_time in list(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) + completed_io.append(pid) + for pid in completed_io: + io_waiting.pop(pid, None) + proc = process_map[pid] + proc.status = self.STATUS_READY + queues[proc.queue_idx].append(proc) # 3. 找最高优先级非空队列 q_idx = -1 @@ -121,6 +123,8 @@ class MLFQScheduler(ProcessScheduler): self.calculate_metrics(p, current_time) completed.append(p) else: + # 时间片用完,更新剩余 burst + p.cpu_bursts[p.current_cpu_idx] = cpu_burst - exec_t p.status = self.STATUS_READY nq = min(q_idx + 1, self.num_queues - 1) p.queue_idx = nq diff --git a/experiment/code/priority.py b/experiment/code/priority.py index 0d755e8..7803f85 100644 --- a/experiment/code/priority.py +++ b/experiment/code/priority.py @@ -35,7 +35,7 @@ class PriorityScheduler(ProcessScheduler): for p in all_processes: heapq.heappush(events, (p.arrival_time, 'arrival', id(p), p)) - ready_queue = [] # (priority, pid, process) + ready_queue = [] # (priority, id, process) completed = [] current_time = 0 @@ -59,40 +59,84 @@ class PriorityScheduler(ProcessScheduler): else: break - _, _, 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 self.preemptive: + # 抢占式: 一次只执行1个时间单位,随时检查更高优先级的到达进程 + _, _, current_process = ready_queue[0] - self.gantt_chart.append((current_time, current_process.pid, 'CPU', cpu_burst)) + if current_process.start_time == -1: + current_process.start_time = current_time - current_time += cpu_burst - current_process.remaining_cpu_time -= cpu_burst - current_process.current_cpu_idx += 1 + current_process.status = self.STATUS_RUNNING - 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)) + if current_process.current_cpu_idx < len(current_process.cpu_bursts): + cpu_burst = current_process.cpu_bursts[current_process.current_cpu_idx] + exec_t = 1 + + self.gantt_chart.append((current_time, current_process.pid, 'CPU', exec_t)) + + current_time += exec_t + current_process.remaining_cpu_time -= exec_t + cpu_burst -= exec_t + current_process.cpu_bursts[current_process.current_cpu_idx] = cpu_burst + + if cpu_burst == 0: + heapq.heappop(ready_queue) # 从就绪队列移除 + 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_process.status = self.STATUS_READY else: + heapq.heappop(ready_queue) 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) + # 非抢占式: 一次执行完整CPU burst + _, _, 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] + + 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_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("Priority (优先级调度)") + algo_name = "Priority (抢占式)" if self.preemptive else "Priority (非抢占式)" + return self.print_results(algo_name) if __name__ == "__main__": diff --git a/experiment/code/rr.py b/experiment/code/rr.py index b98fbe0..55e7a66 100644 --- a/experiment/code/rr.py +++ b/experiment/code/rr.py @@ -37,7 +37,8 @@ class RoundRobinScheduler(ProcessScheduler): ready_queue = deque() completed = [] - io_waiting = {} # {进程PID: IO完成时间} + io_waiting = {} # {pid: IO完成时间} + process_map = {p.pid: p for p in all_processes} # pid -> Process 映射 current_time = 0 max_iterations = 10000 @@ -57,15 +58,16 @@ class RoundRobinScheduler(ProcessScheduler): p.status = self.STATUS_READY ready_queue.append(p) - # 2. 检查 IO 完成 + # 2. 检查 IO 完成 (兜底,防止事件队列遗漏) completed_io = [] - for p, io_end_time in io_waiting.items(): + for pid, io_end_time in list(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) + completed_io.append(pid) + for pid in completed_io: + io_waiting.pop(pid, None) + proc = process_map[pid] + proc.status = self.STATUS_READY + ready_queue.append(proc) if not ready_queue: # 队列为空,推进时间 @@ -93,6 +95,7 @@ class RoundRobinScheduler(ProcessScheduler): p.remaining_cpu_time -= exec_t if exec_t >= cpu_burst: + # CPU burst 完成 p.current_cpu_idx += 1 io_idx = p.current_cpu_idx - 1 if io_idx < len(p.io_bursts): @@ -106,6 +109,8 @@ class RoundRobinScheduler(ProcessScheduler): self.calculate_metrics(p, current_time) completed.append(p) else: + # 时间片用完,更新剩余 burst + p.cpu_bursts[p.current_cpu_idx] = cpu_burst - exec_t p.status = self.STATUS_READY ready_queue.append(p) else: diff --git a/experiment/code/sjf.py b/experiment/code/sjf.py index a321ca5..e0f5991 100644 --- a/experiment/code/sjf.py +++ b/experiment/code/sjf.py @@ -36,18 +36,16 @@ class SJFScheduler(ProcessScheduler): 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 = [] # 就绪队列 (需要排序) + ready_queue = [] completed = [] current_time = 0 while len(completed) < len(all_processes): - # 处理事件 while events and events[0][0] <= current_time: event_time, event_type, uid, p = heapq.heappop(events) @@ -66,40 +64,82 @@ class SJFScheduler(ProcessScheduler): else: break - # 按剩余时间排序 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 self.preemptive: + # SRTF: 一次只执行1个时间单位,随时检查新到达进程 + current_process = ready_queue[0] - self.gantt_chart.append((current_time, current_process.pid, 'CPU', cpu_burst)) + if current_process.start_time == -1: + current_process.start_time = current_time - current_time += cpu_burst - current_process.remaining_cpu_time -= cpu_burst - current_process.current_cpu_idx += 1 + current_process.status = self.STATUS_RUNNING - 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)) + if current_process.current_cpu_idx < len(current_process.cpu_bursts): + cpu_burst = current_process.cpu_bursts[current_process.current_cpu_idx] + exec_t = 1 # 每次只执行1单位 + + self.gantt_chart.append((current_time, current_process.pid, 'CPU', exec_t)) + + current_time += exec_t + current_process.remaining_cpu_time -= exec_t + cpu_burst -= exec_t + current_process.cpu_bursts[current_process.current_cpu_idx] = cpu_burst + + if cpu_burst == 0: + ready_queue.pop(0) # 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_process.status = self.STATUS_READY else: + ready_queue.pop(0) 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) + # SJF 非抢占: 一次执行完整CPU burst + 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_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 algo_name = "SRTF (最短剩余时间优先)" if self.preemptive else "SJF (最短作业优先)"