CoolFace
Datasetpublic

basant307/AI_Governance_Project

sourceHugging Faceapache-2.0updated 2mo agoView on Hugging Face
0likes48downloads
README.md541 linesDownload Raw Back to async-mutex
1[![Build status](https://github.com/DirtyHairy/async-mutex/workflows/Build%20and%20Tests/badge.svg)](https://github.com/DirtyHairy/async-mutex/actions?query=workflow%3A%22Build+and+Tests%22)2[![NPM version](https://badge.fury.io/js/async-mutex.svg)](https://badge.fury.io/js/async-mutex)3[![Coverage Status](https://coveralls.io/repos/github/DirtyHairy/async-mutex/badge.svg?branch=master)](https://coveralls.io/github/DirtyHairy/async-mutex?branch=master)4 5# What is it?6 7This package implements primitives for synchronizing asynchronous operations in8Javascript.9 10## Mutex11 12The term "mutex" usually refers to a data structure used to synchronize13concurrent processes running on different threads. For example, before accessing14a non-threadsafe resource, a thread will lock the mutex. This is guaranteed15to block the thread until no other thread holds a lock on the mutex and thus16enforces exclusive access to the resource. Once the operation is complete, the17thread releases the lock, allowing other threads to acquire a lock and access the18resource.19 20While Javascript is strictly single-threaded, the asynchronous nature of its21execution model allows for race conditions that require similar synchronization22primitives. Consider for example a library communicating with a web worker that23needs to exchange several subsequent messages with the worker in order to achieve24a task. As these messages are exchanged in an asynchronous manner, it is perfectly25possible that the library is called again during this process. Depending on the26way state is handled during the async process, this will lead to race conditions27that are hard to fix and even harder to track down.28 29This library solves the problem by applying the concept of mutexes to Javascript.30Locking the mutex will return a promise that resolves once the mutex becomes31available. Once the async process is complete (usually taking multiple32spins of the event loop), a callback supplied to the caller should be called in order33to release the mutex, allowing the next scheduled worker to execute.34 35# Semaphore36 37Imagine a situation where you need to control access to several instances of38a shared resource. For example, you might want to distribute images between several39worker processes that perform transformations, or you might want to create a web40crawler that performs a defined number of requests in parallel.41 42A semaphore is a data structure that is initialized with an arbitrary integer value and that43can be locked multiple times.44As long as the semaphore value is positive, locking it will return the current value45and the locking process will continue execution immediately; the semaphore will46be decremented upon locking. Releasing the lock will increment the semaphore again.47 48Once the semaphore has reached zero, the next process that attempts to acquire a lock49will be suspended until another process releases its lock and this increments the semaphore50again.51 52This library provides a semaphore implementation for Javascript that is similar to the53mutex implementation described above.54 55# How to use it?56 57## Installation58 59You can install the library into your project via npm60 61    npm install async-mutex62 63The library is written in TypeScript and will work in any environment that64supports ES5, ES6 promises and `Array.isArray`. On ancient browsers,65a shim can be used (e.g. [core-js](https://github.com/zloirock/core-js)).66No external typings are required for using this library with67TypeScript (version >= 2).68 69Starting with Node 12.16 and 13.7, native ES6 style imports are supported.70 71**WARNING:** Node 13 versions < 13.2.0 fail to import this package correctly.72Node 12 and earlier are fine, as are newer versions of Node 13.73 74## Importing75 76**CommonJS:**77```javascript78var Mutex = require('async-mutex').Mutex;79var Semaphore = require('async-mutex').Semaphore;80var withTimeout = require('async-mutex').withTimeout;81```82 83**ES6:**84```javascript85import {Mutex, Semaphore, withTimeout} from 'async-mutex';86```87 88**TypeScript:**89```typescript90import {Mutex, MutexInterface, Semaphore, SemaphoreInterface, withTimeout} from 'async-mutex';91```92 93With the latest version of Node, native ES6 style imports are supported.94 95##  Mutex API96 97### Creating98 99```typescript100const mutex = new Mutex();101```102 103Create a new mutex.104 105### Synchronized code execution106 107Promise style:108```typescript109mutex110    .runExclusive(() => {111        // ...112    })113    .then((result) => {114        // ...115    });116```117 118async/await:119```typescript120await mutex.runExclusive(async () => {121    // ...122});123```124 125`runExclusive` schedules the supplied callback to be run once the mutex is unlocked.126The function may return a promise. Once the promise is resolved or rejected (or immediately after127execution if an immediate value was returned),128the mutex is released. `runExclusive` returns a promise that adopts the state of the function result.129 130The mutex is released and the result rejected if an exception occurs during execution131of the callback.132 133### Manual locking / releasing134 135Promise style:136```typescript137mutex138    .acquire()139    .then(function(release) {140        // ...141 142        release();143    });144```145 146async/await:147```typescript148const release = await mutex.acquire();149try {150    // ...151} finally {152    release();153}154```155 156`acquire` returns an (ES6) promise that will resolve as soon as the mutex is157available. The promise resolves with a function `release` that158must be called once the mutex should be released again. The `release` callback159is idempotent.160 161**IMPORTANT:** Failure to call `release` will hold the mutex locked and will162likely deadlock the application. Make sure to call `release` under all circumstances163and handle exceptions accordingly.164 165### Unscoped release166 167As an alternative to calling the `release` callback returned by `acquire`, the mutex168can be released by calling `release` directly on it:169 170```typescript171mutex.release();172```173 174### Checking whether the mutex is locked175 176```typescript177mutex.isLocked();178```179 180### Cancelling pending locks181 182Pending locks can be cancelled by calling `cancel()` on the mutex. This will reject183all pending locks with `E_CANCELED`:184 185Promise style:186```typescript187import {E_CANCELED} from 'async-mutex';188 189mutex190    .runExclusive(() => {191        // ...192    })193    .then(() => {194        // ...195    })196    .catch(e => {197        if (e === E_CANCELED) {198            // ...199        }200    });201```202 203async/await:204```typescript205import {E_CANCELED} from 'async-mutex';206 207try {208    await mutex.runExclusive(() => {209        // ...210    });211} catch (e) {212    if (e === E_CANCELED) {213        // ...214    }215}216```217 218This works with `acquire`, too:219if `acquire` is used for locking, the resulting promise will reject with `E_CANCELED`.220 221The error that is thrown can be customized by passing a different error to the `Mutex`222constructor:223 224```typescript225const mutex = new Mutex(new Error('fancy custom error'));226```227 228Note that while all pending locks are cancelled, a currently held lock will not be229revoked. In consequence, the mutex may not be available even after `cancel()` has been called.230 231### Waiting until the mutex is available232 233You can wait until the mutex is available without locking it by calling `waitForUnlock()`.234This will return a promise that resolve once the mutex can be acquired again. This operation235will not lock the mutex, and there is no guarantee that the mutex will still be available236once an async barrier has been encountered.237 238Promise style:239```typescript240mutex241    .waitForUnlock()242    .then(() => {243        // ...244    });245```246 247Async/await:248```typescript249await mutex.waitForUnlock();250// ...251```252 253 254##  Semaphore API255 256### Creating257 258```typescript259const semaphore = new Semaphore(initialValue);260```261 262Creates a new semaphore. `initialValue` is an arbitrary integer that defines the263initial value of the semaphore.264 265### Synchronized code execution266 267Promise style:268```typescript269semaphore270    .runExclusive(function(value) {271        // ...272    })273    .then(function(result) {274        // ...275    });276```277 278async/await:279```typescript280await semaphore.runExclusive(async (value) => {281    // ...282});283```284 285`runExclusive` schedules the supplied callback to be run once the semaphore is available.286The callback will receive the current value of the semaphore as its argument.287The function may return a promise. Once the promise is resolved or rejected (or immediately after288execution if an immediate value was returned),289the semaphore is released. `runExclusive` returns a promise that adopts the state of the function result.290 291The semaphore is released and the result rejected if an exception occurs during execution292of the callback.293 294`runExclusive` accepts a first optional argument `weight`. Specifying a `weight` will decrement the295semaphore by the specified value, and the callback will only be invoked once the semaphore's296value greater or equal to `weight`.297 298`runExclusive` accepts a second optional argument `priority`. Specifying a greater value for `priority`299tells the scheduler to run this task before other tasks. `priority` can be any real number. The default300is zero.301 302### Manual locking / releasing303 304Promise style:305```typescript306semaphore307    .acquire()308    .then(function([value, release]) {309        // ...310 311        release();312    });313```314 315async/await:316```typescript317const [value, release] = await semaphore.acquire();318try {319    // ...320} finally {321    release();322}323```324 325`acquire` returns an (ES6) promise that will resolve as soon as the semaphore is326available. The promise resolves to an array with the327first entry being the current value of the semaphore, and the second value a328function that must be called to release the semaphore once the critical operation329has completed. The `release` callback is idempotent.330 331**IMPORTANT:** Failure to call `release` will hold the semaphore locked and will332likely deadlock the application. Make sure to call `release` under all circumstances333and handle exceptions accordingly.334 335`acquire` accepts a first optional argument `weight`. Specifying a `weight` will decrement the336semaphore by the specified value, and the semaphore will only be acquired once its337value is greater or equal to `weight`.338 339`acquire` accepts a second optional argument `priority`. Specifying a greater value for `priority`340tells the scheduler to release the semaphore to the caller before other callers. `priority` can be341any real number. The default is zero.342 343### Unscoped release344 345As an alternative to calling the `release` callback returned by `acquire`, the semaphore346can be released by calling `release` directly on it:347 348```typescript349semaphore.release();350```351 352`release` accepts an optional argument `weight` and increments the semaphore accordingly.353 354**IMPORTANT:** Releasing a previously acquired semaphore with the releaser that was355returned by acquire will automatically increment the semaphore by the correct weight. If356you release by calling the unscoped `release` you have to supply the correct weight357yourself!358 359### Getting the semaphore value360 361```typescript362semaphore.getValue()363```364 365### Checking whether the semaphore is locked366 367```typescript368semaphore.isLocked();369```370 371The semaphore is considered to be locked if its value is either zero or negative.372 373### Setting the semaphore value374 375The value of a semaphore can be set directly to a desired value. A positive value will376cause the semaphore to schedule any pending waiters accordingly.377 378```typescript379semaphore.setValue();380```381 382### Cancelling pending locks383 384Pending locks can be cancelled by calling `cancel()` on the semaphore. This will reject385all pending locks with `E_CANCELED`:386 387Promise style:388```typescript389import {E_CANCELED} from 'async-mutex';390 391semaphore392    .runExclusive(() => {393        // ...394    })395    .then(() => {396        // ...397    })398    .catch(e => {399        if (e === E_CANCELED) {400            // ...401        }402    });403```404 405async/await:406```typescript407import {E_CANCELED} from 'async-mutex';408 409try {410    await semaphore.runExclusive(() => {411        // ...412    });413} catch (e) {414    if (e === E_CANCELED) {415        // ...416    }417}418```419 420This works with `acquire`, too:421if `acquire` is used for locking, the resulting promise will reject with `E_CANCELED`.422 423The error that is thrown can be customized by passing a different error to the `Semaphore`424constructor:425 426```typescript427const semaphore = new Semaphore(2, new Error('fancy custom error'));428```429 430Note that while all pending locks are cancelled, any currently held locks will not be431revoked. In consequence, the semaphore may not be available even after `cancel()` has been called.432 433### Waiting until the semaphore is available434 435You can wait until the semaphore is available without locking it by calling `waitForUnlock()`.436This will return a promise that resolve once the semaphore can be acquired again. This operation437will not lock the semaphore, and there is no guarantee that the semaphore will still be available438once an async barrier has been encountered.439 440Promise style:441```typescript442semaphore443    .waitForUnlock()444    .then(() => {445        // ...446    });447```448 449Async/await:450```typescript451await semaphore.waitForUnlock();452// ...453```454 455`waitForUnlock` accepts optional arguments `weight` and `priority`. The promise will resolve as soon456as it is possible to `acquire` the semaphore with the given weight and priority. Scheduled tasks with457the greatest `priority` values execute first.458 459 460## Limiting the time waiting for a mutex or semaphore to become available461 462Sometimes it is desirable to limit the time a program waits for a mutex or463semaphore to become available. The `withTimeout` decorator can be applied464to both semaphores and mutexes and changes the behavior of `acquire` and465`runExclusive` accordingly.466 467```typescript468import {withTimeout, E_TIMEOUT} from 'async-mutex';469 470const mutexWithTimeout = withTimeout(new Mutex(), 100);471const semaphoreWithTimeout = withTimeout(new Semaphore(5), 100);472```473 474The API of the decorated mutex or semaphore is unchanged.475 476The second argument of `withTimeout` is the timeout in milliseconds. After the477timeout is exceeded, the promise returned by `acquire` and `runExclusive` will478reject with `E_TIMEOUT`. The latter will not run the provided callback in case479of an timeout.480 481The third argument of `withTimeout` is optional and can be used to482customize the error with which the promise is rejected.483 484```typescript485const mutexWithTimeout = withTimeout(new Mutex(), 100, new Error('new fancy error'));486const semaphoreWithTimeout = withTimeout(new Semaphore(5), 100, new Error('new fancy error'));487```488 489### Failing early if the mutex or semaphore is not available490 491A shortcut exists for the case where you do not want to wait for a lock to492be available at all. The `tryAcquire` decorator can be applied to both mutexes493and semaphores and changes the behavior of `acquire` and `runExclusive` to494immediately throw `E_ALREADY_LOCKED` if the mutex is not available.495 496Promise style:497```typescript498import {tryAcquire, E_ALREADY_LOCKED} from 'async-mutex';499 500tryAcquire(semaphoreOrMutex)501    .runExclusive(() => {502        // ...503    })504    .then(() => {505        // ...506    })507    .catch(e => {508        if (e === E_ALREADY_LOCKED) {509            // ...510        }511    });512```513 514async/await:515```typescript516import {tryAcquire, E_ALREADY_LOCKED} from 'async-mutex';517 518try {519    await tryAcquire(semaphoreOrMutex).runExclusive(() => {520        // ...521    });522} catch (e) {523    if (e === E_ALREADY_LOCKED) {524        // ...525    }526}527```528 529Again, the error can be customized by providing a custom error as second argument to530`tryAcquire`.531 532```typescript533tryAcquire(semaphoreOrMutex, new Error('new fancy error'))534    .runExclusive(() => {535        // ...536    });537```538# License539 540Feel free to use this library under the conditions of the MIT license.541 
basant307/AI_Governance_Project · CoolFace