import random
from collections import deque
import json
class PCB:
"""进程控制块(PCB)类"""
def __init__(self, pid, arrive, cpu_total, io_gap):
self.pid = pid # 进程标识符
self.arrive = arrive # 到达时间(ms)
self.cpu_need = cpu_total # 剩余CPU执行时间(ms)
self.cpu_total = cpu_total # 总CPU需求(ms)
self.io_gap = io_gap # I/O阻塞间隔(ms)
self.cpu_since_io = 0 # 距上次I/O已执行时间(ms)
self.state = 'NEW' # 进程状态(NEW/READY/RUN/BLOCK/DONE)
self.queue_level = 0 # 所在队列级别(0/1/2)
self.time_slice_remaining = 0 # 当前队列剩余时间片
self.block_end_time = 0 # 阻塞结束时间
self.start_time = -1 # 首次运行时间
self.finish_time = -1 # 完成时间
self.wait_time = 0 # 总等待时间
self.saved_time_slice = 0 # 保存进入阻塞时的剩余时间片
# 队列配置(三级队列)
QUEUE_CONFIG = {
0: {'time_slice': 2, 'scheduler': 'RR'}, # Q0: 时间片2ms,RR调度
1: {'time_slice': 4, 'scheduler': 'RR'}, # Q1: 时间片4ms,RR调度
2: {'time_slice': float('inf'), 'scheduler': 'FCFS'} # Q2: 无限时间片,FCFS调度
}
def generate_processes(n=20):
"""随机生成n个进程"""
processes = []
for i in range(1, n + 1):
arrive = random.randint(0, 100) # 到达时间范围0-100ms
cpu_total = random.randint(5, 50) # CPU总需求5-50ms
io_gap = random.randint(5, 20) # I/O间隔5-20ms
processes.append(PCB(i, arrive, cpu_total, io_gap))
return processes
def load_processes_from_json(file_path):
"""从JSON文件加载进程数据"""
try:
with open(file_path, 'r') as f:
data = json.load(f)
processes = []
for item in data:
pid = item['pid']
arrive = item['arrive']
cpu_total = item['cpu_total']
io_gap = item.get('io_gap', random.randint(5, 20))
processes.append(PCB(pid, arrive, cpu_total, io_gap))
return processes
except FileNotFoundError:
print(f"错误:文件 {file_path} 未找到。")
return []
except json.JSONDecodeError:
print(f"错误:文件 {file_path} 不是有效的JSON文件。")
return []
def simulate_scheduling(processes, max_time=10000):
"""模拟多级反馈队列调度过程"""
# 初始化系统状态
ready_queues = [deque() for _ in range(3)] # 三级就绪队列
block_queue = deque() # 阻塞队列
completed_processes = [] # 完成的进程
current_process = None # 当前运行进程
system_time = 0 # 系统时间(ms)
cpu_busy_time = 0 # CPU忙时间(ms)
# 甘特图段记录
gantt_segments = []
current_segment = None # 当前甘特图段
# 等待到达的进程
waiting_processes = sorted(processes, key=lambda p: p.arrive)
total_processes = len(processes)
print(f"开始模拟调度...总进程数: {total_processes}")
while len(completed_processes) < total_processes and system_time < max_time:
# 每1000ms输出进度
if system_time % 1000 == 0:
print(f"系统时间: {system_time}ms, 已完成进程: {len(completed_processes)}/{total_processes}")
# 1. 检查新到达的进程
new_process_arrived = False
while waiting_processes and waiting_processes[0].arrive <= system_time:
p = waiting_processes.pop(0)
p.state = 'READY'
p.queue_level = 0
p.time_slice_remaining = QUEUE_CONFIG[0]['time_slice']
ready_queues[0].append(p)
print(f"时间 {system_time}: PID{p.pid} 到达,加入Q0")
new_process_arrived = True
# 2. 检查阻塞进程是否到期
block_process_resumed = False
while block_queue and block_queue[0].block_end_time <= system_time:
p = block_queue.popleft()
p.state = 'READY'
p.cpu_since_io = 0
# 恢复保存的时间片
p.time_slice_remaining = p.saved_time_slice
ready_queues[p.queue_level].append(p)
print(f"时间 {system_time}: PID{p.pid} 结束阻塞,加入Q{p.queue_level}")
block_process_resumed = True
# 3. 如果有新进程到达或阻塞进程恢复,检查是否需要抢占当前进程
if new_process_arrived or block_process_resumed:
if current_process:
# 检查是否有更高优先级的进程就绪
preempt = False
for i in range(current_process.queue_level):
if ready_queues[i]:
preempt = True
break
if preempt:
# 将当前进程放回就绪队列
current_process.state = 'READY'
ready_queues[current_process.queue_level].append(current_process)
print(f"时间 {system_time}: PID{current_process.pid} 被抢占,放回Q{current_process.queue_level}")
current_process = None
# 4. 调度进程(CPU空闲时从高优先级队列获取)
if not current_process:
for i in range(3):
if ready_queues[i]:
current_process = ready_queues[i].popleft()
current_process.state = 'RUN'
if current_process.start_time == -1:
current_process.start_time = system_time
if current_process.time_slice_remaining == 0:
current_process.time_slice_remaining = QUEUE_CONFIG[current_process.queue_level]['time_slice']
print(f"时间 {system_time}: PID{current_process.pid} 开始在Q{current_process.queue_level}运行")
break
current_pid = current_process.pid if current_process else None
is_block = False
if current_process:
# 处理当前进程
current_process.cpu_need -= 1
current_process.cpu_since_io += 1
current_process.time_slice_remaining -= 1
cpu_busy_time += 1
# 检查进程是否完成
if current_process.cpu_need == 0:
current_process.state = 'DONE'
current_process.finish_time = system_time
completed_processes.append(current_process)
print(f"时间 {system_time}: PID{current_process.pid} 完成")
current_process = None
# 处理I/O阻塞
elif current_process.cpu_since_io >= current_process.io_gap and current_process.io_gap > 0:
current_process.cpu_since_io = 0
current_process.state = 'BLOCK'
current_process.block_end_time = system_time + 5 # 阻塞5ms
# 保存当前时间片
current_process.saved_time_slice = current_process.time_slice_remaining
block_queue.append(current_process)
is_block = True
print(f"时间 {system_time}: PID{current_process.pid} 进入阻塞,持续5ms")
current_process = None
# 处理时间片用尽
elif current_process.time_slice_remaining == 0:
next_level = min(current_process.queue_level + 1, 2)
current_process.queue_level = next_level
current_process.state = 'READY'
current_process.time_slice_remaining = QUEUE_CONFIG[next_level]['time_slice']
ready_queues[next_level].append(current_process)
print(f"时间 {system_time}: PID{current_process.pid} 时间片用尽,降级到Q{next_level}")
current_process = None
# 更新甘特图段
if current_segment is None:
current_segment = (system_time, current_pid, is_block)
else:
start_time, pid, block = current_segment
if pid == current_pid and block == is_block:
pass # 同一状态延续
else:
gantt_segments.append((start_time, system_time, pid, block))
current_segment = (system_time, current_pid, is_block)
system_time += 1
# 添加最后一个段
if current_segment is not None:
gantt_segments.append((current_segment[0], system_time, current_segment[1], current_segment[2]))
if system_time >= max_time:
print(f"警告:模拟时间达到上限 {max_time}ms,可能未完成所有进程。"
f"已完成: {len(completed_processes)}/{total_processes}")
return gantt_segments, completed_processes, system_time, cpu_busy_time
def print_gantt_chart(gantt_segments):
"""打印甘特图"""
print("\n===== 甘特图(时间轴步长 1ms)=====")
print("时间区间 进程状态")
for start, end, pid, is_block in gantt_segments:
if pid is None:
continue
status = "(BLOCK)" if is_block else ""
print(f"{start:4d}-{end:4d}: PID{pid}{status}")
def calculate_performance_metrics(completed_processes, system_time, cpu_busy_time):
"""计算并打印性能指标"""
total_turnaround = 0
total_weighted_turnaround = 0
total_waiting_time = 0
print("\n===== 进程性能指标 =====")
for p in completed_processes:
turnaround = p.finish_time - p.arrive
weighted_turnaround = turnaround / p.cpu_total if p.cpu_total != 0 else 0
waiting_time = turnaround - p.cpu_total
total_turnaround += turnaround
total_weighted_turnaround += weighted_turnaround
total_waiting_time += waiting_time
print(f"PID {p.pid:2d} 到达{p.arrive:3d}ms 完成{p.finish_time:3d}ms "
f"周转{turnaround:3d} 带权{weighted_turnaround:.2f} 等待{waiting_time:3d}")
if completed_processes:
avg_turnaround = total_turnaround / len(completed_processes)
cpu_utilization = (cpu_busy_time / system_time) * 100 if system_time > 0 else 0
throughput = len(completed_processes) / (system_time / 1000) if system_time > 0 else 0 # 进程/秒
print("\n===== 系统性能指标 =====")
print(f"平均周转时间: {avg_turnaround:.2f} ms")
print(f"CPU利用率: {cpu_utilization:.2f}%")
print(f"吞吐量: {throughput:.2f} 进程/秒")
else:
print("无完成的进程,无法计算系统性能指标")
return {
"avg_turnaround": avg_turnaround,
"cpu_utilization": cpu_utilization,
"throughput": throughput
}
def main():
"""主函数:执行调度模拟"""
print("===== 多级反馈队列调度模拟 =====")
# 选择输入方式
input_method = input("请选择输入方式(1:随机生成, 2:JSON文件): ")
if input_method == '1':
while True:
try:
n = int(input("请输入要生成的进程数量(≥20): "))
if n >= 20:
break
print("请至少输入20个进程!")
except ValueError:
print("请输入合法整数!")
processes = generate_processes(n)
else:
file_path = input("请输入JSON文件路径: ")
processes = load_processes_from_json(file_path)
if not processes:
return
print(f"模拟进程数: {len(processes)}")
print("进程列表(PID, 到达时间, CPU总需求, I/O间隔):")
for p in processes:
print(f"PID {p.pid:2d}: 到达{p.arrive:3d}ms, 需要{p.cpu_total:3d}ms, I/O间隔{p.io_gap:3d}ms")
# 执行调度模拟
try:
max_time = int(input("请输入最大模拟时间(ms, 默认10000): ") or "10000")
except ValueError:
max_time = 10000
gantt_segments, completed_processes, system_time, cpu_busy_time = simulate_scheduling(processes, max_time)
# 输出结果
print_gantt_chart(gantt_segments)
calculate_performance_metrics(completed_processes, system_time, cpu_busy_time)
if __name__ == "__main__":
main()
这段代码的输出结果我认为有问题:
===== 甘特图(时间轴步长 1ms)=====
时间区间 进程状态
0- 2: PID1
2- 4: PID2
4- 6: PID3
6- 8: PID1
8- 9: PID1(BLOCK)
9- 13: PID2
13- 14: PID3
14- 15: PID3(BLOCK)
15- 16: PID1
16- 17: PID2
17- 18: PID2(BLOCK)
18- 19: PID1
19- 21: PID3
21- 23: PID1
23- 24: PID1(BLOCK)
24- 25: PID3
25- 26: PID3(BLOCK)
26- 33: PID2
33- 34: PID2(BLOCK)
34- 39: PID1
39- 41: PID3
41- 45: PID2
我觉得还有问题,比如”13- 14: PID3
14- 15: PID3(BLOCK)
15- 16: PID1
16- 17: PID2
17- 18: PID2(BLOCK)
18- 19: PID1
19- 21: PID3
21- 23: PID1
23- 24: PID1(BLOCK)“这一段结果应该是13- 14: PID3
14- 15: PID3(BLOCK)
15- 16: PID1
16- 17: PID2
17- 18: PID2(BLOCK)
18- 20: PID1
20- 22: PID3
22- 23: PID1
23- 31: PID2(BLOCK)因为15ms时pid3进入阻塞状态20ms时PID3由阻塞状态进入队列Q1继续执行上次剩余得时间片2ms,然后耗尽Q1队列的时间片后进入队列Q1,此时在队列Q2中的进程顺序为pid2、pid1、pid3,但是由于pid2进入阻塞时的时间为18ms,他重新运行的时间应该是23ms,所以22-23mspid1先运行。你觉得我的想法正确吗
最新发布