fix: 修复进程调度模拟器的CPU利用率计算和深拷贝等bug
- 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
This commit is contained in:
parent
001416e399
commit
4897bef9a6
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,6 +59,49 @@ class PriorityScheduler(ProcessScheduler):
|
|||
else:
|
||||
break
|
||||
|
||||
if self.preemptive:
|
||||
# 抢占式: 一次只执行1个时间单位,随时检查更高优先级的到达进程
|
||||
_, _, current_process = ready_queue[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]
|
||||
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:
|
||||
# 非抢占式: 一次执行完整CPU burst
|
||||
_, _, current_process = heapq.heappop(ready_queue)
|
||||
|
||||
if current_process.start_time == -1:
|
||||
|
|
@ -92,7 +135,8 @@ class PriorityScheduler(ProcessScheduler):
|
|||
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__":
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,8 +64,51 @@ class SJFScheduler(ProcessScheduler):
|
|||
else:
|
||||
break
|
||||
|
||||
# 按剩余时间排序
|
||||
ready_queue.sort(key=lambda p: (p.remaining_cpu_time, id(p)))
|
||||
|
||||
if self.preemptive:
|
||||
# SRTF: 一次只执行1个时间单位,随时检查新到达进程
|
||||
current_process = ready_queue[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]
|
||||
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:
|
||||
# SJF 非抢占: 一次执行完整CPU burst
|
||||
current_process = ready_queue.pop(0)
|
||||
|
||||
if current_process.start_time == -1:
|
||||
|
|
@ -75,7 +116,6 @@ class SJFScheduler(ProcessScheduler):
|
|||
|
||||
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]
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue