Created
December 26, 2021 18:31
-
-
Save gsrai/5482b1403e1a11e90eb1997585484ea0 to your computer and use it in GitHub Desktop.
Async Await Semaphores
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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