Skip to content

Instantly share code, notes, and snippets.

@gsrai
Created December 26, 2021 18:31
Show Gist options
  • Save gsrai/5482b1403e1a11e90eb1997585484ea0 to your computer and use it in GitHub Desktop.
Save gsrai/5482b1403e1a11e90eb1997585484ea0 to your computer and use it in GitHub Desktop.
Async Await Semaphores
class Timer {
startTime
endTime
constructor() {
this.startTime = Date.now();
}
finish() {
this.endTime = Date.now();
}
getElapsedTime() {
const { startTime, endTime } = this;
if (!endTime) {
throw new Error('Did not call finish() for request timer!');
}
return (endTime - startTime) / 1000;
}
}
class RateLimitingSemaphore {
tokens
limit
timeout
constructor(limit = 1, timeout = 1000) {
this.tokens = []
this.limit = limit
this.timeout = timeout
}
release() {
console.log(`releasing semaphore, tokens: ${this.tokens.length}`)
const resolve = this.tokens.shift()
resolve()
}
_acquire(res) {
const { tokens, timeout, limit } = this
if (tokens.length < limit) {
console.log(`acquiring semaphore, tokens: ${this.tokens.length}, limit: ${limit}`)
tokens.push(res)
setTimeout(() => this.release(), 1)
} else {
console.log(`failed to acquire semaphore`)
setTimeout(() => this._acquire(res), timeout)
}
}
async acquire() {
return new Promise((res) => this._acquire(res))
}
}
const sema = new RateLimitingSemaphore(2)
const makeRequest = (id) => new Promise(async (res) => {
await sema.acquire()
console.log(`making request ${id} at ${new Date()}`)
const time = 500 // Math.floor(Math.random() * 1000)
setTimeout(() => {
console.log(`finished request ${id} at ${new Date()}`)
res(time)
}, time)
})
const makeABunchOfRequest = async () => {
let count = 0;
let acc = 0;
while (count < 6) {
const result = await makeRequest(count)
console.log(`request ${count} done at ${new Date()}`)
acc += result;
count++;
}
return acc;
}
const makeParallelRequests = async () => {
const promises = [1, 2, 3, 4, 5, 6].map(id => makeRequest(id))
return Promise.all(promises)
}
const foo = async () => {
const timer = new Timer()
await makeABunchOfRequest()
timer.finish()
console.log(`serial done in ${timer.getElapsedTime()} seconds ๐Ÿ‘`)
}
const bar = async () => {
const timer = new Timer()
await makeParallelRequests()
timer.finish()
console.log(`parallel done in ${timer.getElapsedTime()} seconds ๐Ÿ‘`)
}
async function main() {
await foo()
await bar()
}
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment