【实验题目】:先来先服务FCFS和短作业优先SJF进程调度算法
【实验学时】:4学时
【实验目的】
通过这次实验,加深对进程概念的理解,进一步掌握进程状态的转变、进程调度的策略及对系统性能的评价方法。
【实验内容】
问题描述:
设计程序模拟进程的先来先服务FCFS和短作业优先SJF调度过程。假设有n个进程分别在T1, … ,Tn时刻到达系统,它们需要的服务时间分别为S1, … ,Sn。分别采用先来先服务FCFS和短作业优先SJF进程调度算法进行调度,计算每个进程的完成时间,周转时间和带权周转时间,并且统计n个进程的平均周转时间和平均带权周转时间。
程序要求如下:
1)进程个数n;每个进程的到达时间T1, … ,Tn和服务时间S1, … ,Sn;选择算法1-FCFS,2-SJF。
2)要求采用先来先服务FCFS和短作业优先SJF分别调度进程运行,计算每个进程的周转时间,带权周转时间,并且计算所有进程的平均周转时间,带权平均周转时间;
3)输出:要求模拟整个调度过程,输出每个时刻的进程运行状态,如“时刻3:进程B开始运行”等等;
4)输出:要求输出计算出来的每个进程的周转时间,带权周转时间,所有进程的平均周转时间,带权平均周转时间。
【源代码】复制到Pycharm或者jupyter notebook可以直接跑!!!
"""
先进先出算法,按照进程到达时间排序,首先把所有进程按到达时间进行排序
第一个到达的进程直接服务,后续进程要进行判断,判断该进程到达时间与前一个进程结束时间
若进程到达时间较迟,该进程开始时间等于该进程到达时间,
若进程到达时间较早,该进程开始时间等于前一个进程结束时间。
"""
def FCFS(pcb, n):
pcb.sort(key=lambda x:x[1],reverse=False) #按照到达时间升序排序
#修改pcb中到达时间和完成时间
for i in range(n):
if i == 0: #如果是第一个到达的进程
starttime =int(pcb[i][1]) #开始时间等于第一个进程的到达时间
pcb[i][3] = starttime #修改第一个进程的开始时间
pcb[i][4] = starttime + int(pcb[i][2]) #第一个进程的完成时间等于开始时间+服务时间
elif (i > 0 and int(pcb[i-1][4]) < int(pcb[i][1])): #前一个进程的完成时间早于后一个进程的开始时间
starttime = int(pcb[i][1]) #进程开始时间等于该进程到达时间
pcb[i][3] = starttime #修改开始时间为该进程到达时间
pcb[i][4] = starttime + int(pcb[i][2]) #修改完成时间=开始时间+服务时间
else: #前一个进程的完成时间后于后一个进程的开始时间
starttime = int(pcb[i-1][4]) #该进程开始时间等于前一进程完成时间
pcb[i][3] = starttime #修改
开始时间
pcb[i][4] = starttime + int(pcb[i][2]) #修改完成时间=开始时间+服务时间
#修改pcb中的带权时间和带权周转时间
for i in range(n):
pcb[i][5] = float(pcb[i][4] - int(pcb[i][1])) #带权时间=完成时间-到达时间
pcb[i][6] = float(pcb[i][5] / int(pcb[i][2])) #带权周转时间=带权时间/服务时间
#计算平均周转时间和平均带权周转时间
zztime = 0
dqzztime = 0
for i in range(n):
zztime = float(zztime + float(pcb[i][5])) #周转时间之和
dqzztime = float(dqzztime + float(pcb[i][6])) #带权周转时间之和
average_zztime = float(zztime / n )
average_dqzztime = float(dqzztime / n)
#对pcb按照开始时间进行排序
pcb.sort(key = lambda x:x[3], reverse = False)
return pcb,average_zztime,average_dqzztime
"""
短作业优先算法按作业的服务时间排序,首先按到达时间排序,第一个进程被服务,开始时间等于进程到达时间
后续进程按服务时间进程排序
"""
def SJF(pcb,n):
sjf_pcb = []
i = 1 #控制从第二个进程开始
k = 0 #用于控制循环结束
sjf_pcb = pcb
sjf_pcb.sort(key=lambda x:x[1],reverse=False) #按照到达时间升序排序
#第一个到达的进程先服务,修改第一个进程的周转时间,带权周转时间
starttime = int(sjf_pcb[0][1]) #开始时间等于第一个到达进程的开始时间
pcb[0][3] = starttime #修改第一个进程的开始时间
pcb[0][4] = starttime + int(sjf_pcb[0][2]) #第一个进程的完成时间=开始时间+服务时间
sjf_pcb[0][5] = int(sjf_pcb[0][4]) - int(sjf_pcb[0][1]) #计算周转时间=完成时间-到达时间
sjf_pcb[0][6] = float(sjf_pcb[0][5]) / int(sjf_pcb[0][2]) #计算带权周转时间=周转时间/服务时间
#从第二个进程开始,按服务时间进行排序
temp_pcb = sjf_pcb[1:len(sjf_pcb)] #临时存放
temp_pcb.sort(key=lambda x: x[2], reverse=False) #按服务时间进行升序排序
sjf_pcb[1:len(sjf_pcb)] = temp_pcb #修改原先进程队列,保存按服务时间排序后的进程顺序
#从第二个进程开始
while(i < n):
h = 1
# 比较到达时间和前一者的完成时间
while(int(sjf_pcb[i][1]) >= int(sjf_pcb[i - 1][4])): #当前进程到达时间迟于上一个进程完成时间,开始时间要相应推迟
if i == n - 1: #如果当前进程是已到达最后一个进程,直接修改进程时间
startTime = sjf_pcb[i][1] #开始时间=当前进程到达时间
sjf_pcb[i][3] = starttime #开始时间
sjf_pcb[i][4] = starttime + int(sjf_pcb[i][2]) #完成时间=开始时间+服务时间
sjf_pcb[i][5] = int(sjf_pcb[i][4]) - int(sjf_pcb[i][1]) #周转时间=完成时间-到达时间
sjf_pcb[i][6] = float(sjf_pcb[i][5]) / int(sjf_pcb[i][2]) #带权周转时间=周转时间/服务时间
k = 1 #说明已经服务完已到达的最后一个进程,可以跳出当前while循环
break
else: #如果当前进程不是最后一个进程,服务完之后,还要对进程顺序重新进行调换
temp_sjf_pcb = sjf_pcb[i] #把未被服务的进程放在sjf_pcb列表末尾,便于后续排序
sjf_pcb[i] = sjf_pcb[i+h]
sjf_pcb[i+h] = temp_sjf_pcb
h += 1
if h >= n - i - 1: #说明前面的进程完成之后,还有新的进程没有到达,重新排序(可能新到达的进程服务时间更短)
temp_pcb2 = sjf_pcb[i:len(sjf_pcb)]
temp_pcb2.sort(key=lambda x: x[1], reverse=False) # 后续队列重新按照到达时间顺序进行排序
sjf_pcb[i:len(sjf_pcb)] = temp_pcb2
sjf_pcb[i][3] = int(sjf_pcb[i][1]) #开始时间=该进程的到达时间
sjf_pcb[i][4] = int(sjf_pcb[i][1]) + int(sjf_pcb[i][2]) #完成时间=该进程到达时间+服务时间
sjf_pcb[i][5] = int(sjf_pcb[i][4]) - int(sjf_pcb[i][1]) #周转时间=该进程完成时间-到达时间
sjf_pcb[i][6] = float(sjf_pcb[i][5]) / int(sjf_pcb[i][2]) #带权周转时间=完成时间/服务时间
temp_pcb2 = sjf_pcb[i + 1:len(sjf_pcb)] #保存后续未服务进程
temp_pcb2.sort(key=lambda x: x[2], reverse=False) # 对未服务的进程重新按照服务时间排序
sjf_pcb[i + 1:len(sjf_pcb)] = temp_pcb2 #修改进程队列
h = 1
i += 1
else:
continue
if(k == 1): #说明进程服务完成
break
else: #上一进程结束时,该短进程已经到达,对进程进行时间修改
starttime = sjf_pcb[i - 1][4] #开始时间=前一个进程的完成时间
sjf_pcb[i][3] = starttime #开始时间
sjf_pcb[i][4] = starttime + int(sjf_pcb[i][2]) #完成时间=开始时间+服务时间
sjf_pcb[i][5] = int(sjf_pcb[i][4]) - int(sjf_pcb[i][1])
sjf_pcb[i][6] = float(sjf_pcb[i][5]) / int(sjf_pcb[i][2])
i += 1
# 计算平均周转时间和平均带权周转时间
zztime = 0
dqzztime = 0
for i in range(n):
zzTime = float(zztime + float(pcb[i][5]))
dqzzTime = float(dqzztime + float(pcb[i][6]))
average_zztime = float(zzTime / n)
average_dqzztime = float(dqzzTime / n)
# 输出结果,按照开始时间进行排序
sjf_pcb.sort(key=lambda x: x[3], reverse=False)
return pcb,average_zztime,average_dqzztime
def main():
#实现先来先服务
pcb = []
#确认进程数
n = int(input("请输出进程个数"))
#输入到达时间和服务时间
for i in range(n):
pname = input("请输入第"+str(i+1)+"个进程名:")
arrivetime = input("请输入到达时间:")
servicetime = input("请输入服务时间:")
pcb.append([pname,arrivetime,servicetime,0,0,0,0]) #开始,完成,周转,带权周转
suanfa = input("请输入你想要执行的算法(FCFS或者SJF)")
if suanfa=='FCFS':
pcb,average_zztime,average_dqzztime = FCFS(pcb,n)
else:
pcb,average_zztime,average_dqzztime = SJF(pcb,n)
#输出结果
for i in range(n):
print("进程名: %s 开始时间: %d 完成时间: %d 周转时间: %d 带权周转时间: %.2f " \
% (pcb[i][0], int(pcb[i][3]), int(pcb[i][4]), int(pcb[i][5]), float(pcb[i][6])))
print("本次调度的平均周转时间为: %.2f" % float(average_zztime))
print("本次调度的平均带权周转时间为: %.2f" % float(average_dqzztime))
main()