JS 实现并发控制器

  • Post author:
  • Post category:其他




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 版权协议,转载请附上原文出处链接和本声明。