senfish / blog

个人技术博客
4 stars 0 forks source link

8. 实现一个带并发控制的异步调度器,保证同时运动的任务最多有两个 #8

Open senfish opened 3 years ago

senfish commented 3 years ago
class Scheduler {
  constructor() {}
}

function timeout(time) {
  return new Promise((resolve) => {
    setTimeout(resolve, time);
  });
}
var scheduler = new Scheduler();

function addTask(time, order) {
  scheduler.add(() => timeout(time)).then(() => console.log(order));
}

addTask(1000, 1);
addTask(500, 2);
addTask(300, 3);
addTask(400, 4);

//要求
// ouput : 2 3 1 4
//一开始1,2俩个任务进入队列
//500ms时,2完成,输出2,任务3进入队列
//800ms时,3完成,输出3,任务4进入队列
//1000ms时,1完成,输出1
//1200ms时,4完成,输出4
senfish commented 3 years ago
class Scheduler{
  constructor(pools){
      this.pools = pools || 2; // 当前运行总数量
      this.queue = [];// 任务队列 先进先出
      this.runs = []; // 正运行的任务
  }
  add(task) {
    return new Promise((resolve, reject) => {
      task.resolve = resolve
      this.queue.push(task); // 记录到任务总数里面
      if (this.runs.length < this.pools) {
        this.running()
      }
    })
  }
  running() {
    const task = this.queue.shift();
    this.runs.push(task); // 记录一下当前runs数量
    task().then(() => {
      task.resolve();
      // 执行完了任务之后删除this.runs里面的任务
      this.runs = this.runs.filter(running => running !== task);
      if (this.queue.length > 0) {
        this.running();
      }
    })
  }
}

function timeout(time){
    return new Promise(resolve=>{
        setTimeout(resolve,time)
    })
}
var scheduler = new Scheduler()

function addTask(time,order){
    scheduler
    .add(()=>timeout(time))
    .then(()=>console.log(order))
}

addTask(1000,1)
addTask(500,2)
addTask(300,3)
addTask(400,4)

//要求
// ouput : 2 3 1 4
//一开始1,2俩个任务进入队列
//500ms时,2完成,输出2,任务3进入队列
//800ms时,3完成,输出3,任务4进入队列
//1000ms时,1完成,输出1
//1200ms时,4完成,输出4
senfish commented 5 months ago
class Scheduler {
  constructor(limit) {
    this.queue = []; // 任务队列
    this.running = 0; // 正在运行的个数
    this.limit = limit || 2;
  }
  add(task){
    // 返回的是一个promise,这个promise什么时候resolve呢,要等这个任务(task)成功之后在resolve
    // 那这个任务(task)什么时候成功呢?在这个任务调用之后的then回调函数里面才可以resolve
    return new Promise((resolve, reject) => {
      task.resolve = resolve;
      this.queue.push(task);
      if(this.running < this.limit) {
        this.run();
      }
    })
  }
  run(){
    // 跟给定的任务列表不一样,这个是慢慢收集任务的,所以没办法一开始就直接填满最大并发
    // 所以需要从队列里面一个个吐
    if(this.queue.length === 0) return;
    let task = this.queue.shift();
    this.running++;
    Promise.resolve(task()).then(() => {
      task.resolve();
      this.running--;
      this.run();
    })
  }
}