上篇文章我分享了进程调度算法中的 FIFO,SJF,SRNT 算法。虽说逻辑有点绕,但是分清了调用者和执行者的任务,这个算法就不难了。
这篇文章就来分享时间片轮转调度,和优先级调度算法
时间片轮转调度
javascript
/**
* 从表格中读取数据
*/
class schedule {
time = 0;
executeTask = null;
waitTaskQueue = [];
pendingTaskQueue = [];
finishTask = [];
/** @type {Executer} */
executer = null;
id = null;
lastTaskIndex = 0;
/**
*
* @param {Task[]} taskInfo
*/
constructor(taskInfo) {
this.taskInfo = taskInfo;
this.executer = new Executer(this);
}
addTask(task) {
this.waitTaskQueue.push(task);
}
startSchedule() {
this.id = setInterval(() => {
this.execute();
this.time++;
}, 1000);
}
execute() {
//判断是否还有任务进来
this.judgeNewTask();
//判断任务是否执行完成
if (this.executeTask == null && this.waitTaskQueue.length == 0 && this.taskInfo.length == 0) {
clearInterval(this.id);
return;
}
//判断当前任务是否执行完成,如果执行完成,就上新任务,如果没有,就跳过
this.timeSliceSchedule();
if (this.executeTask) this.executer.execute();
}
fullTimeSlice = 2;
timeSlice = 0;
timeSliceSchedule() {
this.timeSlice++;
if (this.waitTaskQueue.length) {
if (this.timeSlice < this.fullTimeSlice) return;
const newTask = this.waitTaskQueue.shift();
if (this.executeTask == null) {
this.executeTask = newTask;
} else {
this.waitTaskQueue.push(this.executeTask);
this.executeTask = newTask;
}
this.timeSlice = 0;
}
}
judgeNewTask() {
let addedTaskIndex = [];
for (let i = 0; i < this.taskInfo.length; i++) {
if (this.taskInfo[i].arrivalTime <= this.time) {
const { arrivalTime, totalTime, name } = this.taskInfo[i];
this.addTask(new Task(arrivalTime, totalTime, name));
addedTaskIndex.push(i);
this.lastTaskIndex++;
} else {
break;
}
}
this.taskInfo = this.taskInfo.filter((item, index) => {
return addedTaskIndex.includes(index) == false;
});
}
}
这是上篇文章中讲解过的调度者代码,这里就不讲解了。
想要了解更多,可以看这篇文章:🥳每日一练-进程调度算法-JS简易版 - 掘金
主要来看其中实现调度算法的代码:
javascript
fullTimeSlice = 2;
timeSlice = 0;
timeSliceSchedule() {
this.timeSlice++;
if (this.waitTaskQueue.length) {
if (this.executeTask != null && this.timeSlice < this.fullTimeSlice) return;
const newTask = this.waitTaskQueue.shift();
if (this.executeTask == null) {
this.executeTask = newTask;
} else {
this.waitTaskQueue.push(this.executeTask);
this.executeTask = newTask;
}
this.timeSlice = 0;
}
}
首先定义了一个时间片长度的大小:fullTimeSlice
,timeSlice
则定义了用了当前时间片的多少时间,初始值为 0
timeSliceSchedule
方法中,会判断时间片是否用完,以及当前任务是否执行完成。因为任务可能执行完成了,但是时间片还没有用完,这个时候也需要调度新的任务。
如果用完时间片,或者当前任务执行完成了,就要获取最新的任务了。获取最新任务的标准就是按照到达时间,谁先到,谁就先被调度。
代码很简单,大家自己去琢磨里面的道道,就不多解释了
执行代码
javascript
const taskInfo = [
{ name: "A", arrivalTime: 0, totalTime: 3 },
{ name: "B", arrivalTime: 1, totalTime: 2 },
{ name: "C", arrivalTime: 3, totalTime: 3 },
{ name: "D", arrivalTime: 5, totalTime: 1 },
];
new schedule(taskInfo).startSchedule();
输出结果
css
A working... left time is 2
A working... left time is 1
B working... left time is 1
B working... left time is 0
B has finished.
A working... left time is 0
A has finished.
C working... left time is 2
C working... left time is 1
D working... left time is 0
D has finished.
C working... left time is 0
C has finished.
典型的时间片轮转
分析一下结果:
time==0
。 先执行了 A- 执行一个时间周期后,
time==1
。时间片没有用完。B 到了,放入就绪队列中。此时就绪队列:[B] - 执行一个时间周期后,
time==2
。一个时间片用完。 A 重新放到就绪队列队尾,并且从就绪队列队头获取新的 task,获取到的新 task 是 B,所以执行 B。此时就绪队列:[A] - 执行一个时间周期后,
time==3
。时间片没有用完。C 到了,放入就绪队列中。此时就绪队列:[A, C] - 执行一个时间周期后,
time==4
。第二个时间片用完。 并且 B 执行完成。 B 不会放到就绪队列中。然后从就绪队列队头获取新的 task,获取到的新 task 是 A。此时就绪队列:[C] - 执行一个时间周期后,
time==5
。D 到了,放入就绪队列中。此时就绪队列:[C,D]。时间片没有用完(这是第三个时间片)。但 A 执行完成,需要从就绪队列队头获取新的 task,获取到的新 task 是 C。重新计算时间片。此时就绪队列:[D] - 执行一个时间周期后,
time==6
。第四个时间片没有用完,没有新到达的进程. 此时就绪队列:[D] - 执行一个时间周期后,
time==7
。第四个时间片用完。C 重新放到就绪队列队尾,并且从就绪队列队头获取新的 task,获取到的新 task 是 D,所以执行 D。此时就绪队列:[C] - 执行一个时间周期后,
time==8
。第四个时间片没有用完,但 D 执行完成,需要从就绪队列队头获取新的 task,获取到的新 task 是 C。重新计算时间片。此时就绪队列:[] - 执行一个时间周期后,
time==9
。第四个时间片没有用完,但 C 执行完成 。这时就绪队列长度为 0,也没有待到达的进程,所以不会发起新一轮调度,调度结束
是不是很清楚了😄
优先级调度
实现优先级调度需要添加优先级
首先给 Task 对象添加:
diff
class Task {
// ...
// 省略其他代码
+ priority = 0;
- constructor(arrivalTime, totalTime, name) {
+ constructor(arrivalTime, totalTime, name, priority) {
this.arrivalTime = arrivalTime;
this.totalTime = totalTime;
this.leftTime = this.totalTime;
this.name = name || "Task" + Math.random();
+ this.priority = priority || 0;
}
// 省略其他代码
}
然后创建 Task 的时候,需要增加一个参数:
diff
class schedule{
// 省略其他代码
judgeNewTask() {
let addedTaskIndex = [];
for (let i = 0; i < this.taskInfo.length; i++) {
if (this.taskInfo[i].arrivalTime <= this.time) {
- const { arrivalTime, totalTime, name } = this.taskInfo[i];
+ const { arrivalTime, totalTime, name, priority } = this.taskInfo[i];
- this.addTask(new Task(arrivalTime, totalTime, name));
+ this.addTask(new Task(arrivalTime, totalTime, name, priority));
addedTaskIndex.push(i);
this.lastTaskIndex++;
} else {
break;
}
}
this.taskInfo = this.taskInfo.filter((item, index) => {
return addedTaskIndex.includes(index) == false;
});
}
// 省略其他代码
}
调度算法实现:
javascript
class schedule{
// 省略其他代码
execute() {
//判断是否还有任务进来
this.judgeNewTask();
//判断任务是否执行完成
if (this.executeTask == null && this.waitTaskQueue.length == 0 && this.taskInfo.length == 0) {
clearInterval(this.id);
return;
}
//判断当前任务是否执行完成,如果执行完成,就上新任务,如果没有,就跳过
this.prioritySchedule();
if (this.executeTask) this.executer.execute();
}
prioritySchedule() {
if (this.waitTaskQueue.length) {
let index = 0;
for (let i = 0; i < this.waitTaskQueue.length; i++) {
if (this.waitTaskQueue[index].priority < this.waitTaskQueue[i].priority) {
index = i;
}
}
const newTask = this.waitTaskQueue[index];
if (this.executeTask == null) {
this.executeTask = newTask;
this.waitTaskQueue.splice(index, 1);
} else if (this.executeTask.priority < newTask.priority) {
this.waitTaskQueue.push(this.executeTask);
this.executeTask = newTask;
this.waitTaskQueue.splice(index, 1);
}
}
}
// 省略其他代码
}
优先级调度思想,是在当前正在运行的进程和就绪队列的进程中,选出一个优先级最高的进程来运行。和时间片轮转一样,也是抢占式的
执行代码
javascript
const taskInfo = [
{ name: "A", arrivalTime: 0, totalTime: 3, priority: 1 },
{ name: "B", arrivalTime: 1, totalTime: 2, priority: 2 },
{ name: "C", arrivalTime: 3, totalTime: 3, priority: 1 },
{ name: "D", arrivalTime: 5, totalTime: 1, priority: 2 },
];
new schedule(taskInfo).startSchedule();
传入的进程数据,增加了priority
属性
输出结果
css
A working... left time is 2
B working... left time is 1
B working... left time is 0
B has finished.
A working... left time is 1
A working... left time is 0
A has finished.
D working... left time is 0
D has finished.
C working... left time is 2
C working... left time is 1
C working... left time is 0
C has finished.
通过进程数据可以看到,B 会在 A 还没有执行完成的时候就到达,并且 B 的优先级更高, 所以会抢占 A 的执行。对于 C 和 D 也是一样的情况,这就不做分析了
总结:
这篇文章介绍了进程调度算法中的 时间片轮转调度,和优先级调度算法。代码清晰,注释详细,是一篇不可多的的好文章啊
其实还有其他的调度方法,不过算法的实现大同小异,大家可以自己去实现一下。
还有一个小挑战,就是如何将多个调度算法混合在一起,并且代码不混乱,易修改。例如时间片轮转和优先级调度混在一起,或者将时间片和最短执行混在一起。这个要怎么做呢?
喜欢就关注一下吧❤️,你的点赞和关注是我不断分享的动力