手写题 - 实现一个带并发限制的异步调度器

题目

实现一个带并发限制的异步调度器 Scheduler,保证同时运行的任务最多有N个。
完善下面代码中的 Scheduler 类,使得以下程序能正确输出:class Scheduler {add(promiseCreator) { ... }// ...
}const timeout = (time) => new Promise(resolve => {setTimeout(resolve, time)
})const scheduler = new Scheduler(n)
const addTask = (time, order) => {scheduler.add(() => timeout(time)).then(() => console.log(order))
}addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')// 打印顺序是:2 3 1 4

核心思路:考察 Promise知识点;当任务数超过规定任务数,创建微任务进行等待。

代码实现

class Scheduler {constructor(max) {this.max = max;this.count = 0; // 当前执行中的异步操作this.queue = new Array(); // 记录当前的执行数组}async add(promiseCreator) {// count >= max 时,此时先不直接执行,将当前异步操作存储起来,当count满足时,再去执行// Promise.then的链式调用 new Promise((resolve) => { setTimeout(() => {}, 10000}).then xxxxif (this.count >= this.max) {/** 这个new Promise单纯只是为了创建个微任务去等,前面加了await,没有resolve()是不会往下走的 */await new Promise((resolve, reject) => {this.queue.push(resolve);});}/** queue某一项resolve()后会从这儿往下走  */this.count++;let res = await promiseCreator();// 执行timeout(time)this.count--; // 执行完1轮才往下走到这儿if (this.queue.length) {this.queue.shift()();//删除queue数组第一项并执行resolve()}return res;}
}const timeout = (time) => new Promise(resolve => {setTimeout(resolve, time)
})const scheduler = new Scheduler(n) // 任务2=>n即为2
const addTask = (time, order) => {scheduler.add(() => timeout(time)).then(() => console.log(order))
}addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4') 

运行结果如下

在这里插入图片描述

通过输出结果分析代码执行顺序

class Scheduler {constructor(max) {this.max = maxthis.count = 0 this.queue = new Array() }async add(promiseCreator) {if (this.count >= this.max) {await new Promise((resolve, reject) => {this.queue.push(resolve)})}this.count++const res = await promiseCreator()this.count--if (this.queue.length) {this.queue.shift()()}console.log('res: ', res)return res}
}
const timeout = (time) => new Promise(resolve => {console.log('100')setTimeout(resolve, time)
})const scheduler = new Scheduler(2)
const addTask = (time, order) => {scheduler.add(() => timeout(time)).then(() => {console.log(order); return 'timeout'})
}addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')
打印结果:
100
100res: undefined
100
2res: undefined
100
3res: undefined
1res: undefined
4

输出结果分析

  • Part 1:
    (1)addTask1000、addTask500:
    走两次到这儿
    this.count++
    const res = await promiseCreator(); 都输出’100’,先打印2个'100'
    (2)addTask300、addTask400:
    /** 这个new Promise单纯只是为了创建个微任务去等,前面加了await,没有resolve()是不会往下走的 */
    await new Promise((resolve, reject) => {
    this.queue.push(resolve);
    });
  • Part 2:
    (3)500ms的timeout先执行完,setTimeout(resolve, time) resolve后面木有具体值,∴res: undefined
    (4)∵this.queue.shift()()即resolve()是同步代码,
    addTask300走到这儿
    this.count++
    const res = await promiseCreator();
    ∴先打印下一个'100'再return res打印'2'
  • Part 3:
    (5)接下来同理,300ms的timeout先执行完,setTimeout(resolve, time) resolve后面木有具体值,∴res: undefined
    (6)∵this.queue.shift()()即resolve()是同步代码,
    addTask400走到这儿
    this.count++
    const res = await promiseCreator();
    ∴先打印下一个'100'再return res打印'3'
  • Part 4:
    (7)1000ms的timeout先执行完,setTimeout(resolve, time) resolve后面木有具体值,∴res: undefined
    (8)没有下一个’100’了,return res打印'1'
  • Part 5:
    (9)400ms的timeout执行完,setTimeout(resolve, time) resolve后面木有具体值,∴res: undefined
    (10)没有下一个’100’了,return res打印'4'

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/295887.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Quartz.NET 事件监听器

1、调度器监听器 调度器本身收到的一些事件通知,接口ISchedulerListener,如作业的添加、删除、停止、挂起等事件通知,调度器的启动、关闭、出错等事件通知,触发器的暂停、挂起等事件通知,接口部分定义如下&#xff1a…

[已解决]HttpMessageNotReadableException: JSON parse error: Unexpected character:解析JSON时出现异常的问题分析与解决方案

🌷🍁 博主 libin9iOak带您 Go to New World.✨🍁 🦄 个人主页——libin9iOak的博客🎐 🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~&#x1f33…

C# SixLabors.ImageSharp.Drawing的多种用途

生成验证码 /// <summary> /// 生成二维码 /// </summary> /// <param name"webRootPath">wwwroot目录</param> /// <param name"verifyCode">验证码</param> /// <param name"width">图片宽度</…

Docker - 镜像 | 容器 日常开发常用指令 + 演示(一文通关)

目录 Docker 开发常用指令汇总 辅助命令 docker version docker info docker --help 镜像命令 查看镜像信息 下载镜像 搜索镜像 删除镜像 容器命令 查看运行中的容器 运行容器 停止、启动、重启、暂停、恢复容器 杀死容器 删除容器 查看容器日志 进入容器内部…

【数据结构入门精讲 | 第九篇】考研408排序算法专项练习(一)

前面几篇文章介绍的是排序算法&#xff0c;现在让我们开始排序算法的专项练习。 目录 判断题选择题填空题1.插入排序2.另类选择排序3.冒泡排序4.快速查找第K大元 判断题 1.希尔排序是稳定的算法。&#xff08;错&#xff09; 解析&#xff1a;稳定性是指如果两个元素在排序前后…

如何实现酷狗音乐pc页面点击播放时,打开多个歌曲播放时,始终在一个播放页面,(标签页的通讯)

大致有两种思路&#xff0c; 一种是通过wind.open()方法传第二个参数&#xff0c; A页面&#xff1a; //点击跳转播放页函数function toPlayPage(){window.open(path/xxxx/xxxx?name音乐名,music)//第二个参数写一个定值&#xff0c;代表跳转页面都为music标签页&#xff0…

vue.js组件的应用(Vite构建)

一.组件的定义和应用 1.全局组件 全局组件是指在任何页面中不必再单独引入组件并注册&#xff0c;直接在模板中使用组件名称就可以引用的组件。 全局组件注册方法一 先在src目录下新建一个globalComponents文件夹&#xff0c;再新建一个Header.vue的全局组件。 <templa…

Web前端 ---- 【Vue】vue路由守卫(全局前置路由守卫、全局后置路由守卫、局部路由path守卫、局部路由component守卫)

目录 前言 全局前置路由守卫 全局后置路由守卫 局部路由守卫之path守卫 局部路由守卫之component守卫 前言 本文介绍Vue2最后的知识点&#xff0c;关于vue的路由守卫。也就是鉴权&#xff0c;不是所有的组件任何人都可以访问到的&#xff0c;需要权限&#xff0c;而根据权限…

Java经典框架之Spring

Java经典框架之Spring Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c;Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. Spring简介 2.…

RabbitMQ不公平分发与预取值

1.分发简介 RabbitMQ不设置的话默认采用轮询方式分发消息,你一个我一个(公平);但实际生活中,由于处理速度不同,若还采用轮询方式分发会导致处理速度快的空等待,因此我们采用不公平分发 2.不公平分发 在消费者这侧设置即可,以之前的Worker3和Worker4为例 2.1.Worker3 packa…

通过windows cng api 实现rsa非对称加密

参考&#xff1a; 1,使用 CNG 加密数据 - Win32 apps | Microsoft Learn 2,不记得了 &#xff08;下文通过cng api演示rsa加密&#xff0c;不做原理性介绍&#xff09; 相对于aes等对称加密算法&#xff0c;rsa加密算法不可逆性更强。非对称加密在通常情况下&#xff0c;使…

异步消息原理

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 在日常开发中&#xff…