Skip to content

Instantly share code, notes, and snippets.

@shotamatsuda
Last active February 5, 2017 11:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shotamatsuda/f54d2106d4d603ca38d9e95e9deb34d2 to your computer and use it in GitHub Desktop.
Save shotamatsuda/f54d2106d4d603ca38d9e95e9deb34d2 to your computer and use it in GitHub Desktop.
Promise based semaphore
import { Namespace } from '../core/Namespace'
export const internal = Namespace('Semaphore')
class Task {
constructor(semaphore, callback) {
const promises = [
new Promise((resolve, reject) => {
this.resolve = resolve
this.reject = reject
}),
new Promise(resolve => {
this.let = resolve
}).then(() => {
callback(this.resolve, this.reject)
}),
]
this.promise = Promise.all(promises)
.then(values => {
semaphore.signal()
return values[0]
}, reason => {
semaphore.signal()
return Promise.reject(reason)
})
}
}
export class Semaphore {
constructor(capacity) {
const scope = internal(this)
scope.capacity = capacity
scope.available = capacity
scope.queue = []
}
wait(callback) {
const scope = internal(this)
const task = new Task(this, callback)
if (scope.available === 0) {
scope.queue.push(task)
} else {
--scope.available
task.let()
}
return task.promise
}
signal() {
const scope = internal(this)
if (scope.queue.length === 0) {
++scope.available
} else {
scope.queue.shift().let()
}
}
// Properties
get capacity() {
const scope = internal(this)
return scope.capacity
}
get available() {
const scope = internal(this)
return scope.available
}
}
import { Semaphore } from 'core/Semaphore'
const should = require('should')
describe('Semaphore', () => {
it('runs tasks below or equal its capacity', () => {
const semaphore = new Semaphore(10)
let count = 0
for (let i = 0; i < 1000; ++i) {
semaphore.wait((resolve, reject) => {
++count
count.should.belowOrEqual(10)
setTimeout(() => {
--count
count.should.belowOrEqual(10)
resolve()
}, 100)
})
}
})
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment