网络拓扑与进程调度结合模拟:在 Python 中创建一个网状网络拓扑,在每个节点上模拟操作系统的进程调度(使用如 FCFS、SJF 等算法),模拟数据在网络节点间的传输过程中,同时考虑进程调度对数据传输效率和可靠性的影响。例如,当节点上的进程调度繁忙时,数据传输可能会延迟,分析这种情况下网络的整体性能。
import tkinter as tk from tkinter import ttk, scrolledtext import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg import numpy as np import random import heapq from enum import Enum from collections import deque, defaultdict from matplotlib.figure import Figure # 设置随机种子以便结果可重现 random.seed(42) class Process: """表示一个需要调度和执行的进程""" def __init__(self, pid, arrival_time, burst_time, data_size=0): self.pid = pid # 进程ID self.arrival_time = arrival_time # 到达时间 self.burst_time = burst_time # 执行时间 self.remaining_time = burst_time # 剩余执行时间 self.start_time = None # 首次执行时间 self.completion_time = None # 完成时间 self.waiting_time = 0 # 等待时间 self.turnaround_time = 0 # 周转时间 self.data_size = data_size # 数据大小(如果是网络相关进程) def __repr__(self): return f"Process(pid={self.pid}, arrival_time={self.arrival_time}, burst_time={self.burst_time})" class SchedulingAlgorithm(Enum): """调度算法枚举""" FCFS = 1 # 先来先服务 SJF = 2 # 最短作业优先 RR = 3 # 时间片轮转 class DataPacket: """表示网络中的数据包""" def __init__(self, packet_id, source, destination, size): self.packet_id = packet_id # 数据包ID self.source = source # 源节点 self.destination = destination # 目标节点 self.size = size # 数据包大小(影响处理时间) self.arrival_time = 0 # 到达时间 self.hops = 0 # 经过的跳数 self.dropped = False # 是否被丢弃 self.current_position = None # 当前位置(用于动画) self.progress = 0 # 传输进度(0-100) def __repr__(self): return f"Packet(id={self.packet_id}, size={self.size})" class NetworkNode: """表示网络中的一个节点""" def __init__(self, node_id, x, y, scheduling_algorithm=SchedulingAlgorithm.FCFS, time_quantum=2): self.node_id = node_id # 节点ID self.x = x # x坐标(用于可视化) self.y = y # y坐标(用于可视化) self.scheduling_algorithm = scheduling_algorithm # 调度算法 self.time_quantum = time_quantum # 时间片大小(用于RR算法) self.process_queue = [] # 进程队列 self.executing_process = None # 当前执行的进程 self.time = 0 # 节点内部时间 self.finished_processes = [] # 已完成的进程 self.network_queue = deque() # 网络数据包队列 self.neighbors = [] # 邻居节点列表 self.performance_metrics = { 'avg_waiting_time': 0, 'avg_turnaround_time': 0, 'throughput': 0, 'packet_delay': [] } self.current_packet = None # 当前正在处理的数据包 self.packet_processing_time = 0 # 处理当前数据包的剩余时间 self.active_packets = [] # 正在从该节点发送的数据包 def add_neighbor(self, neighbor_node): """添加邻居节点""" self.neighbors.append(neighbor_node) def add_process(self, process): """添加新进程到队列""" process.arrival_time = self.time # 设置到达时间为当前节点时间 self.process_queue.append(process) def add_packet(self, packet): """添加数据包到网络队列""" packet.arrival_time = self.time # 记录到达时间 self.network_queue.append(packet) def update_performance_metrics(self): """更新性能指标""" if self.finished_processes: total_waiting_time = sum(p.waiting_time for p in self.finished_processes) total_turnaround_time = sum(p.turnaround_time for p in self.finished_processes) self.performance_metrics['avg_waiting_time'] = total_waiting_time / len(self.finished_processes) self.performance_metrics['avg_turnaround_time'] = total_turnaround_time / len(self.finished_processes) if self.performance_metrics['packet_delay']: self.performance_metrics['throughput'] = len(self.performance_metrics['packet_delay']) / max(1, self.time) def select_next_process(self): """根据调度算法选择下一个要执行的进程""" if not self.process_queue: return None if self.scheduling_algorithm == SchedulingAlgorithm.FCFS: # 按到达时间排序 self.process_queue.sort(key=lambda p: p.arrival_time) return self.process_queue.pop(0) elif self.scheduling_algorithm == SchedulingAlgorithm.SJF: # 按执行时间排序(最短作业优先) self.process_queue.sort(key=lambda p: p.burst_time) return self.process_queue.pop(0) elif self.scheduling_algorithm == SchedulingAlgorithm.RR: # 轮转调度:从队列头部取出,执行一个时间片后放回尾部 if not hasattr(self, 'rr_queue'): self.rr_queue = deque(self.process_queue) self.process_queue = [] if not self.rr_queue: return None process = self.rr_queue.popleft() return process return None def process_packet(self): """处理网络数据包""" if self.current_packet is None and self.network_queue: self.current_packet = self.network_queue.popleft() # 处理时间与数据包大小成正比 self.packet_processing_time = self.current_packet.size if self.current_packet is not None: # 处理数据包 self.packet_processing_time -= 1 if self.packet_processing_time <= 0: # 数据包处理完成,转发到下一个节点 self.forward_packet(self.current_packet) # 记录延迟 delay = self.time - self.current_packet.arrival_time self.performance_metrics['packet_delay'].append(delay) self.current_packet = None self.packet_processing_time = 0 def forward_packet(self, packet): """将数据包转发到下一个节点""" if not self.neighbors: # 没有邻居节点,数据包丢弃 packet.dropped = True return # 随机选择一个邻居节点转发 next_node = random.choice(self.neighbors) # 设置数据包的当前位置和目标位置 packet.current_position = (self.x, self.y) packet.target_node = next_node packet.progress = 0 # 添加到活动数据包列表 self.active_packets.append(packet) def execute(self, time_units=1): """执行一个时间单位的模拟""" execution_log = [] for _ in range(time_units): self.time += 1 # 更新活动数据包的位置 for packet in self.active_packets[:]: packet.progress += 10 # 每次更新10%的进度 if packet.progress >= 100: # 数据包到达目标节点 packet.hops += 1 packet.target_node.add_packet(packet) self.active_packets.remove(packet) # 处理网络数据包 self.process_packet() # 如果当前有执行的进程,继续执行 if self.executing_process: self.executing_process.remaining_time -= 1 # 记录执行信息 log_entry = f"时间 {self.time}: 节点 {self.node_id} 正在执行进程 {self.executing_process.pid} " \ f"(剩余时间: {self.executing_process.remaining_time})" execution_log.append(log_entry) # 检查进程是否完成 if self.executing_process.remaining_time <= 0: self.executing_process.completion_time = self.time self.executing_process.turnaround_time = self.executing_process.completion_time - self.executing_process.arrival_time self.executing_process.waiting_time = self.executing_process.turnaround_time - self.executing_process.burst_time self.finished_processes.append(self.executing_process) # 记录完成信息 log_entry = f"时间 {self.time}: 节点 {self.node_id} 完成进程 {self.executing_process.pid} " \ f"(周转时间: {self.executing_process.turnaround_time}, 等待时间: {self.executing_process.waiting_time})" execution_log.append(log_entry) # 如果是网络数据包相关的进程,处理完后创建数据包 if self.executing_process.data_size > 0: packet = DataPacket( packet_id=len(self.performance_metrics['packet_delay']) + 1, source=self, destination=None, # 目的地将在网络层确定 size=self.executing_process.data_size ) self.add_packet(packet) log_entry = f"时间 {self.time}: 节点 {self.node_id} 生成数据包 {packet.packet_id} (大小: {packet.size})" execution_log.append(log_entry) self.executing_process = None # 如果是RR算法,检查队列中是否有更多进程 if self.scheduling_algorithm == SchedulingAlgorithm.RR and hasattr(self, 'rr_queue') and self.rr_queue: self.executing_process = self.rr_queue.popleft() # 对于RR算法,检查时间片是否用完 elif self.scheduling_algorithm == SchedulingAlgorithm.RR: # 减少时间片计数 if not hasattr(self, 'time_quantum_count'): self.time_quantum_count = self.time_quantum self.time_quantum_count -= 1 if self.time_quantum_count <= 0: # 时间片用完,将进程放回队列尾部 self.rr_queue.append(self.executing_process) self.executing_process = None self.time_quantum_count = self.time_quantum # 如果当前没有执行的进程,选择一个新进程 if self.executing_process is None: self.executing_process = self.select_next_process() if self.executing_process: if self.executing_process.start_time is None: self.executing_process.start_time = self.time # 记录开始执行信息 log_entry = f"时间 {self.time}: 节点 {self.node_id} 开始执行进程 {self.executing_process.pid} " \ f"(执行时间: {self.executing_process.burst_time})" execution_log.append(log_entry) # 更新性能指标 self.update_performance_metrics() return execution_log class MeshNetwork: """表示网状网络拓扑""" def __init__(self, num_nodes, connectivity=2, scheduling_algorithm=SchedulingAlgorithm.FCFS, time_quantum=2): self.num_nodes = num_nodes # 节点数量 self.connectivity = connectivity # 每个节点的连接数 self.nodes = [] # 节点列表 self.time = 0 # 网络全局时间 self.scheduling_algorithm = scheduling_algorithm self.time_quantum = time_quantum self.execution_logs = [] # 执行日志 # 创建节点(环形布局) angles = np.linspace(0, 2 * np.pi, num_nodes, endpoint=False) radius = 200 # 圆环半径 for i in range(num_nodes): x = 250 + radius * np.cos(angles[i]) # +250是为了将图形居中 y = 250 + radius * np.sin(angles[i]) node = NetworkNode( node_id=i, x=x, y=y, scheduling_algorithm=scheduling_algorithm, time_quantum=time_quantum ) self.nodes.append(node) # 构建网状连接 self.build_mesh_topology() def build_mesh_topology(self): """构建网状拓扑结构""" # 使用环形连接作为基础,然后添加随机连接 for i in range(self.num_nodes): # 连接到下一个节点(形成环) next_node = (i + 1) % self.num_nodes self.nodes[i].add_neighbor(self.nodes[next_node]) # 添加额外的随机连接 for _ in range(self.connectivity - 1): # 随机选择一个不相邻的节点 possible_neighbors = [j for j in range(self.num_nodes) if j != i and j != next_node and j not in [n.node_id for n in self.nodes[i].neighbors]] if possible_neighbors: neighbor_idx = random.choice(possible_neighbors) self.nodes[i].add_neighbor(self.nodes[neighbor_idx]) def generate_processes(self, num_processes_per_node, burst_time_range=(1, 10), data_size_range=(1, 5)): """为每个节点生成随机进程""" for node in self.nodes: for i in range(num_processes_per_node): burst_time = random.randint(*burst_time_range) # 50%的概率是网络相关进程,需要生成数据包 data_size = random.randint(*data_size_range) if random.random() > 0.5 else 0 process = Process( pid=f"{node.node_id}-{i}", arrival_time=0, # 将在节点添加进程时设置 burst_time=burst_time, data_size=data_size ) node.add_process(process) def run_simulation(self, time_units=1): """运行模拟指定的时间单位""" all_logs = [] for _ in range(time_units): self.time += 1 # 每个节点执行一个时间单位 for node in self.nodes: logs = node.execute() all_logs.extend(logs) self.execution_logs.extend(all_logs) return all_logs def get_average_performance(self): """获取整个网络的平均性能指标""" avg_metrics = { 'avg_waiting_time': 0, 'avg_turnaround_time': 0, 'avg_throughput': 0, 'avg_packet_delay': 0, 'avg_hops': 0, 'completed_processes': 0, 'total_processes': 0 } all_delays = [] all_hops = [] for node in self.nodes: avg_metrics['avg_waiting_time'] += node.performance_metrics['avg_waiting_time'] avg_metrics['avg_turnaround_time'] += node.performance_metrics['avg_turnaround_time'] avg_metrics['avg_throughput'] += node.performance_metrics['throughput'] all_delays.extend(node.performance_metrics['packet_delay']) all_hops.extend([p.hops for p in node.performance_metrics['packet_delay'] if hasattr(p, 'hops')]) avg_metrics['completed_processes'] += len(node.finished_processes) avg_metrics['total_processes'] += len(node.finished_processes) + len(node.process_queue) if hasattr(node, 'rr_queue'): avg_metrics['total_processes'] += len(node.rr_queue) # 计算平均值 if self.nodes: avg_metrics['avg_waiting_time'] /= len(self.nodes) avg_metrics['avg_turnaround_time'] /= len(self.nodes) avg_metrics['avg_throughput'] /= len(self.nodes) if all_delays: avg_metrics['avg_packet_delay'] = sum(all_delays) / len(all_delays) if all_hops: avg_metrics['avg_hops'] = sum(all_hops) / len(all_hops) return avg_metrics def visualize_network(self, canvas): """在给定的画布上可视化网络拓扑结构和数据包传输""" # 清除画布 canvas.delete("all") # 绘制节点间的连接 for node in self.nodes: for neighbor in node.neighbors: if node.node_id < neighbor.node_id: # 避免重复绘制 canvas.create_line(node.x, node.y, neighbor.x, neighbor.y, fill="#CCCCCC", width=1) # 绘制节点 node_colors = ["#3498db", "#e74c3c", "#2ecc71", "#f39c12", "#9b59b6", "#1abc9c", "#d35400", "#27ae60", "#8e44ad", "#c0392b"] for i, node in enumerate(self.nodes): color = node_colors[i % len(node_colors)] # 节点圆圈 canvas.create_oval(node.x - 15, node.y - 15, node.x + 15, node.y + 15, fill=color, outline="black") # 节点ID文本 canvas.create_text(node.x, node.y, text=str(node.node_id), fill="white", font=("Arial", 10, "bold")) # 显示节点上的进程数量 process_count = len(node.process_queue) if hasattr(node, 'rr_queue'): process_count += len(node.rr_queue) if node.executing_process: process_count += 1 canvas.create_text(node.x, node.y + 25, text=f"进程:{process_count}", fill="black", font=("Arial", 9)) # 显示节点上的数据包数量 packet_count = len(node.network_queue) if node.current_packet: packet_count += 1 canvas.create_text(node.x, node.y + 40, text=f"数据包:{packet_count}", fill="black", font=("Arial", 9)) # 绘制活动数据包 for node in self.nodes: for packet in node.active_packets: # 计算数据包的当前位置 target_x, target_y = packet.target_node.x, packet.target_node.y progress = packet.progress / 100.0 current_x = node.x + (target_x - node.x) * progress current_y = node.y + (target_y - node.y) * progress # 根据数据包大小确定圆圈大小 size_factor = 5 + packet.size * 2 # 绘制数据包 canvas.create_oval(current_x - size_factor / 2, current_y - size_factor / 2, current_x + size_factor / 2, current_y + size_factor / 2, fill="#f1c40f", outline="black") # 绘制数据包ID canvas.create_text(current_x, current_y, text=str(packet.packet_id), fill="black", font=("Arial", 8)) class NetworkSimulationGUI: """网络模拟图形界面""" def __init__(self, root): self.root = root self.root.title("网络拓扑与进程调度模拟") self.root.geometry("1200x700") # 创建主框架 main_frame = ttk.Frame(root) main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 左侧框架 - 网络可视化 left_frame = ttk.LabelFrame(main_frame, text="网络传输模拟") left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5) # 创建画布用于网络可视化 self.network_canvas = tk.Canvas(left_frame, width=500, height=500, bg="white") self.network_canvas.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) # 控制面板 control_frame = ttk.Frame(left_frame) control_frame.pack(fill=tk.X, padx=5, pady=5) ttk.Label(control_frame, text="时间片大小:").pack(side=tk.LEFT, padx=5) self.time_quantum_var = tk.IntVar(value=2) ttk.Entry(control_frame, textvariable=self.time_quantum_var, width=5).pack(side=tk.LEFT, padx=5) ttk.Label(control_frame, text="调度算法:").pack(side=tk.LEFT, padx=5) self.algorithm_var = tk.StringVar(value="RR") algorithm_combo = ttk.Combobox(control_frame, textvariable=self.algorithm_var, values=["FCFS", "SJF", "RR"], width=8) algorithm_combo.pack(side=tk.LEFT, padx=5) self.run_button = ttk.Button(control_frame, text="运行模拟", command=self.run_simulation) self.run_button.pack(side=tk.LEFT, padx=5) self.step_button = ttk.Button(control_frame, text="单步执行", command=self.step_simulation) self.step_button.pack(side=tk.LEFT, padx=5) self.reset_button = ttk.Button(control_frame, text="重置", command=self.reset_simulation) self.reset_button.pack(side=tk.LEFT, padx=5) self.analysis_button = ttk.Button(control_frame, text="性能分析", command=self.show_analysis) self.analysis_button.pack(side=tk.LEFT, padx=5) # 右侧框架 - 运行信息 right_frame = ttk.LabelFrame(main_frame, text="运行信息") right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5) # 创建文本区域用于显示日志 self.log_text = scrolledtext.ScrolledText(right_frame, wrap=tk.WORD, height=20) self.log_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) # 创建状态栏 self.status_var = tk.StringVar(value="就绪") self.status_bar = ttk.Label(root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W) self.status_bar.pack(side=tk.BOTTOM, fill=tk.X) # 初始化网络 self.reset_simulation() def reset_simulation(self): """重置模拟""" # 清空日志 self.log_text.delete(1.0, tk.END) # 获取算法设置 algorithm_map = { "FCFS": SchedulingAlgorithm.FCFS, "SJF": SchedulingAlgorithm.SJF, "RR": SchedulingAlgorithm.RR } algorithm = algorithm_map[self.algorithm_var.get()] time_quantum = self.time_quantum_var.get() # 创建网络 self.network = MeshNetwork( num_nodes=10, connectivity=3, scheduling_algorithm=algorithm, time_quantum=time_quantum ) # 为每个节点生成进程 self.network.generate_processes(num_processes_per_node=5) # 更新可视化 self.network.visualize_network(self.network_canvas) # 更新状态栏 self.status_var.set(f"模拟已重置 - 时间: {self.network.time}") # 启用按钮 self.run_button.config(state=tk.NORMAL) self.step_button.config(state=tk.NORMAL) self.analysis_button.config(state=tk.NORMAL) # 添加初始日志 self.log_text.insert(tk.END, "模拟已重置\n") self.log_text.insert(tk.END, f"使用调度算法: {self.algorithm_var.get()}\n") self.log_text.insert(tk.END, f"时间片大小: {time_quantum}\n\n") def step_simulation(self): """单步执行模拟""" if not hasattr(self, 'network'): self.reset_simulation() # 执行一个时间单位 logs = self.network.run_simulation(time_units=1) # 更新可视化 self.network.visualize_network(self.network_canvas) # 更新日志 for log in logs: self.log_text.insert(tk.END, log + "\n") self.log_text.see(tk.END) # 滚动到底部 # 更新状态栏 self.status_var.set(f"模拟运行中 - 时间: {self.network.time}") def run_simulation(self): """运行完整模拟""" if not hasattr(self, 'network'): self.reset_simulation() # 禁用按钮防止重复点击 self.run_button.config(state=tk.DISABLED) self.step_button.config(state=tk.DISABLED) # 更新状态栏 self.status_var.set(f"模拟运行中 - 时间: {self.network.time}") # 运行50个时间单位 for _ in range(50): logs = self.network.run_simulation(time_units=1) # 更新可视化 self.network.visualize_network(self.network_canvas) # 更新日志 for log in logs: self.log_text.insert(tk.END, log + "\n") self.log_text.see(tk.END) # 滚动到底部 # 更新状态栏 self.status_var.set(f"模拟运行中 - 时间: {self.network.time}") # 让界面有时间更新 self.root.update_idletasks() # 重新启用按钮 self.run_button.config(state=tk.NORMAL) self.step_button.config(state=tk.NORMAL) # 更新状态栏 self.status_var.set(f"模拟完成 - 时间: {self.network.time}") def show_analysis(self): """显示性能分析窗口""" if not hasattr(self, 'network'): self.reset_simulation() # 创建新窗口 analysis_window = tk.Toplevel(self.root) analysis_window.title("性能分析") analysis_window.geometry("800x600") # 创建标签页 notebook = ttk.Notebook(analysis_window) notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 性能指标标签页 metrics_frame = ttk.Frame(notebook) notebook.add(metrics_frame, text="性能指标") # 获取性能指标 metrics = self.network.get_average_performance() # 创建性能指标表格 metrics_tree = ttk.Treeview(metrics_frame, columns=("指标", "值"), show="headings") metrics_tree.heading("指标", text="性能指标") metrics_tree.heading("值", text="数值") metrics_tree.column("指标", width=300) metrics_tree.column("值", width=150) metrics_tree.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 添加性能指标 metrics_tree.insert("", tk.END, values=("平均等待时间", f"{metrics['avg_waiting_time']:.2f}")) metrics_tree.insert("", tk.END, values=("平均周转时间", f"{metrics['avg_turnaround_time']:.2f}")) metrics_tree.insert("", tk.END, values=("吞吐量", f"{metrics['avg_throughput']:.2f}")) metrics_tree.insert("", tk.END, values=("平均数据包延迟", f"{metrics['avg_packet_delay']:.2f}")) metrics_tree.insert("", tk.END, values=("平均跳数", f"{metrics['avg_hops']:.2f}")) metrics_tree.insert("", tk.END, values=("已完成进程数", f"{metrics['completed_processes']}")) metrics_tree.insert("", tk.END, values=("总进程数", f"{metrics['total_processes']}")) # 算法分析标签页 analysis_frame = ttk.Frame(notebook) notebook.add(analysis_frame, text="算法分析") # 添加分析文本 analysis_text = scrolledtext.ScrolledText(analysis_frame, wrap=tk.WORD) analysis_text.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) analysis_content = """ 进程调度算法分析 1. 最短作业优先(SJF)算法 优点: - 平均等待时间和周转时间通常最优,能有效提高系统吞吐量 - 短作业能够快速完成,减少了整体响应时间 - 在作业执行时间差异较大的情况下表现尤为出色 缺点: - 需要预先知道作业执行时间,这在实际系统中往往难以实现 - 对长作业不利,可能导致长作业长时间得不到处理(饥饿现象) - 无法适应动态到达的作业流 适用场景: - 批处理系统,作业执行时间可预测的场景 - 作业执行时间差异较大的环境 - 对系统吞吐量要求较高的场景 2. 时间片轮转(RR)算法 优点: - 公平性好,每个进程都能在一定时间内得到处理 - 响应时间快,适合交互式系统,用户体验较好 - 实现简单,不需要预先知道作业执行时间 缺点: - 时间片设置过小将增加上下文切换开销,降低系统效率 - 时间片设置过大则退化为FCFS算法,失去RR的优势 - 平均周转时间通常比SJF长 适用场景: - 分时系统,需要快速响应的交互式系统 - 作业执行时间相近的环境 - 对公平性要求较高的场景 3. 先来先服务(FCFS)算法 优点: - 实现简单,公平性较好 - 没有饥饿现象,每个进程最终都会被执行 缺点: - 长作业可能导致短作业长时间等待 - 平均等待时间和周转时间通常不是最优 - 不适合需要快速响应的系统 适用场景: - 对响应时间要求不高的批处理系统 - 作业执行时间相近的环境 在本次模拟中: - 平均等待时间为 {avg_waiting_time:.2f} - 平均周转时间为 {avg_turnaround_time:.2f} - 吞吐量为 {avg_throughput:.2f} - 平均数据包延迟为 {avg_packet_delay:.2f} 结论: - 选择调度算法时,需要根据系统类型、作业特性和性能目标综合考虑 - 对于网络环境,RR算法通常更适合,因为它提供了更好的公平性和响应时间 - 时间片大小对RR算法的性能影响很大,需要根据系统特性合理设置 """.format(**metrics) analysis_text.insert(tk.END, analysis_content) analysis_text.config(state=tk.DISABLED) # 设为只读 # 性能比较标签页 compare_frame = ttk.Frame(notebook) notebook.add(compare_frame, text="算法比较") # 添加比较按钮 compare_button = ttk.Button(compare_frame, text="比较不同算法", command=lambda: self.compare_algorithms(compare_frame)) compare_button.pack(pady=10) # 初始显示提示信息 ttk.Label(compare_frame, text="点击上方按钮比较不同调度算法的性能").pack(pady=20) def compare_algorithms(self, parent_frame): """比较不同调度算法的性能""" # 清除现有内容 for widget in parent_frame.winfo_children(): widget.destroy() # 创建图表 fig = Figure(figsize=(7, 5), dpi=100) # 获取当前网络配置 num_nodes = self.network.num_nodes connectivity = self.network.connectivity # 比较三种算法 algorithms = [ (SchedulingAlgorithm.FCFS, "FCFS"), (SchedulingAlgorithm.SJF, "SJF"), (SchedulingAlgorithm.RR, "RR") ] results = {} for algorithm, name in algorithms: # 创建新的网络实例 network = MeshNetwork( num_nodes=num_nodes, connectivity=connectivity, scheduling_algorithm=algorithm, time_quantum=self.time_quantum_var.get() ) # 生成相同的进程集 network.generate_processes(num_processes_per_node=5) # 运行模拟 for _ in range(50): network.run_simulation(time_units=1) # 收集结果 results[name] = network.get_average_performance() # 绘制比较图表 metrics = ['avg_waiting_time', 'avg_turnaround_time', 'avg_throughput', 'avg_packet_delay'] metric_names = ['平均等待时间', '平均周转时间', '吞吐量', '平均数据包延迟'] for i, metric in enumerate(metrics): ax = fig.add_subplot(2, 2, i + 1) values = [results[alg][metric] for alg in results.keys()] ax.bar(results.keys(), values, color=['blue', 'green', 'orange']) ax.set_title(metric_names[i]) ax.set_ylabel(metric_names[i].split('(')[0]) # 添加数值标签 for j, v in enumerate(values): ax.text(j, v + 0.05 * max(values), f'{v:.2f}', ha='center') fig.tight_layout() # 在Tkinter中显示图表 canvas = FigureCanvasTkAgg(fig, master=parent_frame) canvas.draw() canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True) if __name__ == "__main__": root = tk.Tk() app = NetworkSimulationGUI(root) root.mainloop()