JS 实现并发控制器
JS 实现并发控制器
前言
好久没有产出过一篇博客,因为最近一直在对自己的项目忙前忙后。写这篇文章的动机是,见到了一道面试题,觉得挺有意思,于是写出来和大家分享,也说一下我的思路。
题目
实现一个 Scheduler,让同时进行的任务在同一时间不超过两个,输出如下
class Scheduler {
add(promiseCreactor) {...}
}
const timeout = time => new Promise(resolve => setTimeout(resolve, time))
const scheduler = new Scheduler()
const addTask = (time, order) => scheduler.add(() => timeout(time).then(() => console.info(order)))
addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')
/**
* output:
* 2
* 3
* 1
* 4
*/
题外话
虽然这篇博文是想说 js 怎么实现,语言其实也无关紧要了,我想用 csp 的思路来解决这道题,看一下如何用 Golang 解决。
var limiter = make(chan struct{}, 1)
func task() {
// ... some time consuming operate
}
func main() {
for {
limiter <- struct{}{}
task()
<- limiter
}
}
创建一个缓冲为 1 的 channel,如果缓冲区的数据 > 1 的时候就会阻塞,在每次执行
task
的之前加入一个
struct{}{}
,在执行完毕后会将
struct{}{}
取出,这样就可以一直保持同一个时间点只会有两个任务同时执行。
如果用 CSP 来实现并发限制,重要的是在 js 中实现 channel,下面看一下 JS 的实现
解决方案
channel.js
module.exports = class Chan {
constructor(limitCount = 0){
this.limitCount = limitCount + 1
this.locks = []
this.values = []
}
async push(value){
if(this.values.length >= this.limitCount){
await new Promise(resolve => this.locks.push(resolve))
}
this.values.push(value)
}
get(){
(this.locks.shift() || (() => {}))()
return this.values.shift()
}
}
main.js
(题目)
const Chan = require('./channel')
const chan = new Chan(1)
class Scheduler {
async add(promiseCreactor) {
await chan.push(1)
await promiseCreactor()
chan.get()
}
}
const timeout = time => new Promise(resolve => setTimeout(resolve, time))
const scheduler = new Scheduler(2)
const addTask = (time, order) => scheduler.add(() => timeout(time).then(() => console.info(order)))
addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')
输出:
2
3
1
4
思想上和 Golang 的 chan 是一样的,这样可以简单的实现并发限制,并且有很高的灵活性,比如我想限制同一时间只有三个任务可以同时进行,那么我只需要设置 limitCount 为 2 就行了
const chan = new Chan(2)
输出
3
2
4
1
版权声明:本文为HaoDaWang原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。