一、课程设计的主要内容
模拟实现多级反馈队列调度算法,要求设置不少于5个反馈队列,并通过菜单输入反馈队列的个数、优先级、时间片长度,以及其他补充的参数(加分项)。
要求完成以下功能:
(1)输入各个进程的进入时间和估计运行时间。
(2)计算各个进程的开始时间、结束时间、周转时间、带权周转时间,平均周转时间、平均带权周转时间,并直观输出显示。
(3)要求动态演示各个进程的运行情况状态,以及各个队列的运行情况。
二、需求分析
1、模拟实现多级反馈队列调度算法,要求设置不少于5个反馈队列,并通过菜单输入反馈队列的个数、优先级、时间片长度
多级反馈队列运行情况如下所示:
多级反馈队列算法:
设置多个就绪队列,分别赋予不同的优先级,如逐级降低,每个队列时间片长度也不同,优先级越低则时间片越长,如逐级加倍,新进程进入内存后,先投入队列1的末尾,按FCFS算法调度。若按队列1一个时间片未能执行完,则降低投入到队列2的末尾,同样按FCFS算法调度。如此下去,降低到最后的队列,则按"时间片轮转"算法调度直到完成。
仅当较高优先级的队列为空,才调度较低优先级的队列中的进程执行,如果进程执行时有新进程进入较高优先级的队列,则抢先执行新进程,并把被抢占的进程投入原队列的末尾。
2、输入各个进程的进入时刻和估计运行时间
各个进程的进入时刻和估计运行时时间用于后续多级反馈队列调度算法使用。
3、计算各个进程的开始时间、结束时间、周转时间、带权周转时间,平均周转时间、平均带权周转时间,并直观输出显示
周转时间=作业完成时刻—作业到达时刻;
带权周转时间=周转时间/服务时间;
平均周转时间=作业周转总时间/作业个数;
平均带权周转时间=带权周转总时间/作业个数;
所以首先要通过多级反馈队列算法对所有的作业进行调度,计算出作业完成时刻才能够计算出相应的周转时间以及带权周转时间。
4、动态演示各个进程的运行情况状态,以及各个队列的运行情况
动态演示可以帮助我们直观地了解进程的运行情况和队列的状态。通过观察动态演示结果,我们可以判断调度算法是否合理,并根据需要进行改进。
三 、概要设计
1、模块设计
整个程序被分为以下三个模块:
数据输入模块:
可视化界面提示用户输入,将用户输入的信息发送到后端进行处理
多级反馈队列调度算法执行模块:
最主要的部分,接受用户输入数据,进行相关处理后用于执行多级反馈队列算法
结果显示模块:
将结果直观输出显示
2、模块关系
四 、详细设计
1、实验原理分析设计
对于多级反馈队列,根据用户输入的队列信息按照优先级的逆序对队列进行排序,即进程首先被分配到优先级高的运行。并为前n-1(若有n个队列)个添加标识符为1的属性,表明如果该队列时间片用完后,进程剩余时间大于0,则将进程加入到下一级队列的队尾,第n个队列标识符为0,表示如果该队列时间片用完后,进程剩余时间大于0,则将进程加入到该队列的队尾。多级反馈队可抢占的特性的实现,是将用户输入的各个进程的进入时间添加一个列表存储,表示在这些时刻有可能会发生抢占。当进程在队列中运行时,首先会判断该进程在该队列时间片内运行时是否可能发生抢占,如果不会发生抢占,则“大胆”的运行,如果会发生抢占就“小心谨慎”的运行。
2、程序输入输出分析设计
对于程序输入输出,采用Fastapi框架,用两个页面实现:
数据输入界面如下:
结果输出界面如下:
五 调试分析
1、抢占问题
抢占时刻下一秒,被抢占的进程是没有运行的,而是直接添加到运行时的队列的队尾,在前期运行时,未考虑到此情况,导致算的结果有误差:
错误结果:
改进后的正确结果:
抢占后未将可能抢占的时间从存储可能抢占时间的列表中删除,导致死循环,后经改进解决了此问题。
2、队列问题
在进程未运行完需要加入下一队列时未考虑好最低级队列导致地址越界:
后经过改进解决了此问题。
六 测试结果
1、结果分析
队列信息:
进程信息:
抢占时运行情况:
自行分析:
经反复分析验证,运行结果无误。
七 用户使用说明
启动支持python的编译器,安装相关环境,打开源程序,运行。访问浏览器访问:http://127.0.0.1:8000 打开网页如下:
如图所示操作,点击提交按钮:
结果显示如图:
动态运行情况在编译器终端显示:
八 课程设计总结
在本次实验中,我成功地模拟实现了多级反馈队列调度算法,并完成了实验要求的各项功能,包括输入进程信息、计算各个进程的运行时间和指标,以及动态演示进程的运行情况和队列的状态。以下是我对实验的一些心得和体会:
深入理解调度算法原理:在开始实验之前,我仔细学习了多级反馈队列调度算法的原理和实现方式。理解了各个队列的优先级和时间片长度的设置对进程调度的影响。
设计合理的用户界面:为了方便输入队列参数和进程信息,我设计了一个简单的菜单界面。通过菜单输入方式,用户可以灵活设置队列的个数、优先级、时间片长度等参数。这样的设计提高了实验的可定制性和易用性。
准确计算运行指标:根据输入的进程信息和队列参数,我实现了计算各个进程的开始时间、结束时间、周转时间和带权周转时间的功能。通过这些指标,我能够评估调度算法的性能,并对比不同设置下的结果。确保计算准确性对于实验的结果分析和结论的正确性至关重要。
动态演示增强可视化效果:实验要求实现动态演示功能,我将运行情况打印在终端展示进程的运行情况和队列的调度情况。这种方式更直观地展示了进程的状态和队列的运行情况,使实验结果更易于理解和分析。动态演示对于展示调度算法的效果和改进空间有着重要的作用。
通过本次实验,我对多级反馈队列调度算法有了更深入的了解,并成功地实现了模拟。我认识到合理的算法设计、准确的计算和直观的结果展示是实验中的关键要素。实验过程中,我锻炼了问题分析和解决的能力,并学会了如何利用实验结果来评估算法性能和进行改进。这对于进一步深入学习操作系统和进程调度算法有着重要的意义。
代码
main.py
import uvicorn
import time
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
"""
周转时间=作业完成时刻—作业到达时刻;
带权周转时间=周转时间/服务时间;
平均周转时间=作业周转总时间/作业个数;
平均带权周转时间=带权周转总时间/作业个数;
"""
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")
# 首页路由
@app.get("/")
def index(request: Request):
return templates.TemplateResponse("index.html", {
"request": request})
# 处理表单提交
@app.post("/process_form")
async def process_form(request: Request):
form_data = await request.form()
queue_count = int(form_data["queueCount"])
process_count = int(form_data["processCount"])
# 创建一个空列表,用于存储队列
queues = []
# 使用循环创建指定数量的队列
for i in range(queue_count):
priority = int(form_data[f"priority_{
i}"])
time_slice = int(form_data[f"time_slice_{
i}"])
queue = {
"优先级": priority, "时间片": time_slice, "标记位": 1} # 创建一个包含优先级、时间片和标记位属性的字典
queues.append(queue) # 将队列添加到列表中
# 对队列列表按优先级从高到低进行排序
queues.sort(key=lambda x: (-x["优先级"], x["时间片"]))
# 为队列中的每个字典添加队列标号
for i, queue in enumerate(queues):
queue["队列标号"] = i + 1
# 将最后一个队列的标记位置为0,表示该队列不能将进程加载到下一队列中
if queues:
queues[-1]["标记位"] = 0
# 打印创建的队列
for queue in queues:
print(f"队列{
queue['队列标号']}: {
queue}")
# 创建一个空列表,用于存储所有的进程
jincheng = []
#用于存储可能的抢占时间
qiangzhanshijian =[]
# 使用循环创建指定数量的进程
for i in range(process_count):
enter_time = int(form_data[f"arrival_time_{
i}"])
runtime = int(form_data[f"run_time_{
i}"])
qiangzhanshijian.append(enter_time)
dictionary = {
"进程": i + 1,
"进入时刻": enter_time,
"估计运行时间": runtime,
"剩余运行时间": runtime,
"开始时刻": 0,
"结束时刻": 0,
} # 创建一个包含进入时刻、估计运行时间、开始时刻、结束时刻和标记位属性的字典
jincheng.append(dictionary) # 将字典添加到列表中
print(f"可能的抢占时间: {
qiangzhanshijian}")
# 打印创建的进程
for i, dictionary in enumerate(jincheng):
print(f"进程{
i + 1}: {
dictionary}")
# 创建一个空列表,用于存储满足进入时刻条件的字典
filtered_jincheng = [[] for _ in range(queue_count)]
shijian = 0