Edited at

Promise で排他制御を行う

Promise での非同期処理時、排他制御を怠ったばっかりにバグを出してしまった、そんな経験ありませんか。私はあります。

スレッドを使う場合、Mutex や synchronized 等々、大抵排他制御を行うライブラリや構文などがセットでついてくるのだけど、Promise/A+ には無いので自前で制御する必要がある。

なので、Promise で排他制御が出来るライブラリを npm から調べ、めぼしい物二つをピックアップしてみた。


async-lock


  • https://www.npmjs.com/package/async-lock


  • 一番メジャーっぽいライブラリ。ダウンロード数も多い。



  • ロック取得時、key を指定する


    • redis の key の set のように、key ごとに排他制御したい場合に便利



  • タイムアウトのサポート


  • 待ち受けタスク数の上限のサポート


インターフェイスが、acquire の引数に排他処理の関数を書くタイプ。

const lock = new AsyncLock();

await lock.acquire(key, () => {
// 排他処理
});


await-semaphore


  • https://www.npmjs.com/package/await-semaphore



  • セマフォを実現するライブラリ



  • シンプルな実装


  • TypeScript 対応


  • new Semaphore(n) でアクセス出来る数を指定できることはもちろん、バイナリセマフォであるnew Mutex()なインターフェイスがあったりする


acquire と use という、Promise がロック解除用の関数を返すインターフェイスと、引数に排他処理で実行したい関数を書くタイプ二つがある。

const mutex = new Mutex();

const release = await mutex.acquire();
try {
// 排他処理
} finally {
// release を呼び出さないとデットロックになる
release();
}

mutex.use(() => {

// 排他処理
});


どちらを使うか

用途に合わせて使えば良いのだけど、単にシンプルな Mutex での排他制御がしたいだけなら、await-semaphoreが、色々やりたかったら async-lock が良いと思う。