🥳每日一练-进程调度算法二-JS简易版

上篇文章我分享了进程调度算法中的 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;
  }
}

首先定义了一个时间片长度的大小:fullTimeSlicetimeSlice则定义了用了当前时间片的多少时间,初始值为 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. 

典型的时间片轮转

分析一下结果:

  1. time==0。 先执行了 A
  2. 执行一个时间周期后,time==1。时间片没有用完。B 到了,放入就绪队列中。此时就绪队列:[B]
  3. 执行一个时间周期后,time==2。一个时间片用完。 A 重新放到就绪队列队尾,并且从就绪队列队头获取新的 task,获取到的新 task 是 B,所以执行 B。此时就绪队列:[A]
  4. 执行一个时间周期后,time==3。时间片没有用完。C 到了,放入就绪队列中。此时就绪队列:[A, C]
  5. 执行一个时间周期后,time==4。第二个时间片用完。 并且 B 执行完成。 B 不会放到就绪队列中。然后从就绪队列队头获取新的 task,获取到的新 task 是 A。此时就绪队列:[C]
  6. 执行一个时间周期后,time==5。D 到了,放入就绪队列中。此时就绪队列:[C,D]。时间片没有用完(这是第三个时间片)。但 A 执行完成,需要从就绪队列队头获取新的 task,获取到的新 task 是 C。重新计算时间片。此时就绪队列:[D]
  7. 执行一个时间周期后,time==6。第四个时间片没有用完,没有新到达的进程. 此时就绪队列:[D]
  8. 执行一个时间周期后,time==7。第四个时间片用完。C 重新放到就绪队列队尾,并且从就绪队列队头获取新的 task,获取到的新 task 是 D,所以执行 D。此时就绪队列:[C]
  9. 执行一个时间周期后,time==8。第四个时间片没有用完,但 D 执行完成,需要从就绪队列队头获取新的 task,获取到的新 task 是 C。重新计算时间片。此时就绪队列:[]
  10. 执行一个时间周期后,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 也是一样的情况,这就不做分析了

总结:

这篇文章介绍了进程调度算法中的 时间片轮转调度,和优先级调度算法。代码清晰,注释详细,是一篇不可多的的好文章啊

其实还有其他的调度方法,不过算法的实现大同小异,大家可以自己去实现一下。

还有一个小挑战,就是如何将多个调度算法混合在一起,并且代码不混乱,易修改。例如时间片轮转和优先级调度混在一起,或者将时间片和最短执行混在一起。这个要怎么做呢?

喜欢就关注一下吧❤️,你的点赞和关注是我不断分享的动力

相关推荐
电院工程师16 分钟前
SM3算法C语言实现(无第三方库,带测试)
c语言·算法·安全·密码学
Hello.Reader1 小时前
RediSearch 查询语法速览
前端·算法
generallizhong1 小时前
android 省市区联动选择
android·java·算法
YGGP3 小时前
LeetCode 662. 二叉树的最大宽度
算法
周圣贤5 小时前
九尾狐编程语言新算法“超维时空演算体”
开发语言·算法
随缘而动,随遇而安6 小时前
第八十二篇 大数据开发基础:树形数据结构深度解析与实战指南(附创新生活案例)
大数据·开发语言·数据结构
codingandsleeping6 小时前
重读《你不知道的JavaScript》(上)- this
前端·javascript
孩子 你要相信光8 小时前
前端如何通过 Blob 下载 Excel 文件
前端·javascript
药9558 小时前
数据结构 4 (栈和队列)
java·开发语言·数据结构
喵喵侠w8 小时前
腾讯地图Web版解决热力图被轮廓覆盖的问题
前端·javascript