Simple, dependency-free Semaphore tools for ES6.
npm install @debonet/es6semaphore
es6semaphore provides a Promises-based semaphore object for tracking resources or other operations whose concurrency must be limited.
wait()
and signal()
have the typical Semaphore semantics
and can be used as Promises
or with async/await
syntax, e.g.:
const sem = new Semaphore(2);
// wait until a resource is available, then claim one
await sem.wait();
// do something sensitive
...
// release the resource freeing up other events to proceed
sem.signal();
Here's an example:
const Semaphore = require( "@debonet/es6semaphore" );
const sem = new Semaphore(2);
const timeStart = new Date().getTime();
async function f(ch) {
await sem.wait();
await sleep(1000);
console.log( "Here with",ch,'at', new Date().getTime() - tmStart; );
sem.signal();
}
// these will run two at a time, taking two seconds to complete
f('a');
f('b');
f('c');
f('d');
and generate an output somthing like:
Here with a at 1005
Here with b at 1005
Here with c at 2007
Here widh d at 2008
Sometimes it's useful to wait on the semaphore without claiming a resource. A series of functions are available for various tests
when( test )
whenAll()
whenNone()
whenAny()
for example:
f('a');
f('b');
f('c');
f('d');
console.log("all have been queued");
await sem.when(c => c==1 );
console.log("one is available");
await sem.whenAll();
console.log("all are available");
will produce:
all have been queued
Here with a at 1005
Here with b at 1005
Here with c at 2007
one is available
Here widh d at 2008
all are available
Waits until the indicated number of resources are available, and then claims them before resolving
Use with await
const semaphore = new Semaphore(2);
await sem.wait();
// do whatever
or with Promise chains:
sem.wait().then( /* do whatever */ );
Releases control over the indicated number of semaphore resources allowing the next tasks waiting for control to proceed.
const semaphore = new Semaphore( 5 );
await sem.wait( );
// do whatever
sem.signal( );
the number of resources remaining
the total number of resources available
these functions allow events to await some semaphore condition before proceeding. All work with async/await
or as Promises
Proceeds when any of the resources remain unused (i.e. when remaining() > 0
)
Example:
sem.whenAny().then( /* do something */)
Proceeds when all of the resources are unused (i.e. when remaining() == available()
)
Example:
await sem.whenAll();
// do something
Proceeds when none of the resources remain ununsed (i.e. when all have been used, remaining() == 0
)
these methods allow for generalized tests, and claim amounts
Proceeds when the provided test function evaluates to true given the number of resources that are currently remaining and the available number of resources
// wait for three resources to be remaining
sem.when( c => c == 3);
// do whatever
Claims the indicated number of resources requested when the provided test function evaluates to true.
// wait for there to be at least two more resources than the 3 we're requesting
sem.getWhen( 3, (remaining, requested, available) => remaining > requested + 2 )
// do whatever
sem.release( 3 );
With care, an existing semaphore can be reconfigured using the following methods. In particular, no guarantees are made to ensure that release() is not called too many times in the case that the available number of resources is reduced, or the remaining number of resources is increased.
Resets the total available resources. Checks to see if the new configuration releases any waiting promises
Resets the total remaining resources. Checks to see if the new configuration releases any waiting promises
definition of sleep()
used in the example above
function sleep( dtm ){
return new Promise( fOk => setTimeout( fOk, dtm ));
}