Last active
May 17, 2018 23:31
-
-
Save hugoferreira/e52e373cf8c34971bbca6aae1bb6df6d to your computer and use it in GitHub Desktop.
Asynchronous Bounded Queue
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 AsyncQueue<T> { | |
| waitingEnqueue = new Array<() => void>() | |
| waitingDequeue = new Array<() => void>() | |
| enqueuePointer = 0 | |
| dequeuePointer = 0 | |
| queue = Array<T>() | |
| maxSize = 1 | |
| async enqueue(x: T) { | |
| if ((this.queue.length + 1) > this.maxSize || this.waitingDequeue.length > 0) { | |
| this.dequeuePointer += 1 | |
| await new Promise(r => this.waitingDequeue.unshift(r)) | |
| this.waitingDequeue.pop() | |
| } | |
| this.queue.unshift(x) | |
| if (this.enqueuePointer > 0) { | |
| this.waitingEnqueue[this.enqueuePointer-1]() | |
| this.enqueuePointer -= 1 | |
| } | |
| } | |
| async dequeue() { | |
| if (this.queue.length == 0 || this.waitingEnqueue.length > 0) { | |
| this.enqueuePointer += 1 | |
| await new Promise(r => this.waitingEnqueue.unshift(r)) | |
| this.waitingEnqueue.pop() | |
| } | |
| if (this.dequeuePointer > 0) { | |
| this.waitingDequeue[this.dequeuePointer - 1]() | |
| this.dequeuePointer -= 1 | |
| } | |
| return this.queue.pop()! | |
| } | |
| } |
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 AsyncSemaphore { | |
| private promises = Array<() => void>() | |
| constructor(private i: number) {} | |
| signal() { | |
| if (this.promises.length > 0) this.promises.pop()() | |
| this.i += 1 | |
| } | |
| async wait() { | |
| if (this.i == 0 || this.promises.length > 0) | |
| await new Promise(r => this.promises.unshift(r)) | |
| this.i -= 1 | |
| } | |
| } | |
| class AsyncQueue<T> { | |
| private queue = Array<T>() | |
| private waitingEnqueue: AsyncSemaphore | |
| private waitingDequeue: AsyncSemaphore | |
| constructor(readonly maxSize: number) { | |
| this.waitingEnqueue = new AsyncSemaphore(0) | |
| this.waitingDequeue = new AsyncSemaphore(maxSize) | |
| } | |
| async enqueue(x: T) { | |
| await this.waitingDequeue.wait() | |
| this.queue.unshift(x) | |
| this.waitingEnqueue.signal() | |
| } | |
| async dequeue() { | |
| await this.waitingEnqueue.wait() | |
| this.waitingDequeue.signal() | |
| return this.queue.pop()! | |
| } | |
| } |
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 AsyncQueue<T> { | |
| waitingEnqueue = new Array<() => void>() | |
| waitingDequeue = new Array<() => void>() | |
| enqueuePointer = 0 | |
| dequeuePointer = 0 | |
| queue = Array<T>() | |
| maxSize = 1 | |
| trace = 0 | |
| async enqueue(x: T) { | |
| this.trace += 1 | |
| const localTrace = this.trace | |
| if ((this.queue.length + 1) > this.maxSize || this.waitingDequeue.length > 0) { | |
| console.debug(`[${localTrace}] Producer Waiting`) | |
| this.dequeuePointer += 1 | |
| await new Promise(r => this.waitingDequeue.unshift(r)) | |
| this.waitingDequeue.pop() | |
| console.debug(`[${localTrace}] Producer Ready`) | |
| } | |
| this.queue.unshift(x) | |
| console.debug(`[${localTrace}] Enqueueing ${x} Queue is now [${this.queue.join(', ')}]`) | |
| if (this.enqueuePointer > 0) { | |
| console.debug(`[${localTrace}] Notify Consumer`) | |
| this.waitingEnqueue[this.enqueuePointer-1]() | |
| this.enqueuePointer -= 1 | |
| } | |
| } | |
| async dequeue() { | |
| this.trace += 1 | |
| const localTrace = this.trace | |
| console.debug(`[${localTrace}] Queue length before pop: ${this.queue.length}`) | |
| if (this.queue.length == 0 || this.waitingEnqueue.length > 0) { | |
| console.debug(`[${localTrace}] Consumer Waiting`) | |
| this.enqueuePointer += 1 | |
| await new Promise(r => this.waitingEnqueue.unshift(r)) | |
| this.waitingEnqueue.pop() | |
| console.debug(`[${localTrace}] Consumer Ready`) | |
| } | |
| const x = this.queue.pop()! | |
| console.debug(`[${localTrace}] Queue length after pop: ${this.queue.length} Popping ${x}`) | |
| if (this.dequeuePointer > 0) { | |
| console.debug(`[${localTrace}] Notify Producer`) | |
| this.waitingDequeue[this.dequeuePointer - 1]() | |
| this.dequeuePointer -= 1 | |
| } | |
| return x | |
| } | |
| } |
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
| async function produce<T>(q: AsyncQueue<T>, x: T) { | |
| await q.enqueue(x) | |
| } | |
| async function consume<T>(q: AsyncQueue<T>) { | |
| return await q.dequeue() | |
| } | |
| (async () => { | |
| const q = new AsyncQueue<number>() | |
| consume(q).then(console.log) | |
| consume(q).then(console.log) | |
| produce(q, 3) | |
| produce(q, 4) | |
| consume(q).then(console.log) | |
| consume(q).then(console.log) | |
| produce(q, 5) | |
| produce(q, 6) | |
| produce(q, 7) | |
| produce(q, 8) | |
| consume(q).then(console.log) | |
| consume(q).then(console.log) | |
| })() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment