🥳每日一练-进程调度算法二-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 也是一样的情况,这就不做分析了

总结:

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

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

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

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

相关推荐
Anson Jiang10 小时前
浏览器标签页管理:使用chrome.tabs API实现新建、切换、抓取内容——Chrome插件开发从入门到精通系列教程06
开发语言·前端·javascript·chrome·ecmascript·chrome devtools·chrome插件
掘金安东尼10 小时前
黑客劫持:周下载量超20+亿的NPM包被攻击
前端·javascript·面试
小柴狗10 小时前
C语言关键字详解:static、const、volatile
算法
剑亦未配妥11 小时前
移动端触摸事件与鼠标事件的触发机制详解
前端·javascript
仙俊红12 小时前
LeetCode每日一题,20250914
算法·leetcode·职场和发展
风中的微尘19 小时前
39.网络流入门
开发语言·网络·c++·算法
前端君19 小时前
实现最大异步并发执行队列
javascript
西红柿维生素20 小时前
JVM相关总结
java·jvm·算法
知识分享小能手20 小时前
React学习教程,从入门到精通,React 组件核心语法知识点详解(类组件体系)(19)
前端·javascript·vue.js·学习·react.js·react·anti-design-vue
蚂蚁RichLab前端团队21 小时前
🚀🚀🚀 RichLab - 花呗前端团队招贤纳士 - 【转岗/内推/社招】
前端·javascript·人工智能