非同期キーベースのロック: 断続的なファイル アクセス エラーの原因
ImageProcessor ライブラリのキャッシュ メカニズムはキーに基づく非同期ロックを採用しているため、断続的なファイル アクセス エラーが発生します。 これは、AsyncDuplicateLock
クラス内の設計上の欠陥が原因です。
欠陥: セマフォの早期リリース
元の AsyncDuplicateLock
コードは、セマフォを解放する前に SemaphoreSlim
から ConcurrentDictionary
インスタンスを途中で削除します。これにより、セマフォが削除後にアクセスされる可能性があるため、過剰なセマフォ チャーンと潜在的なエラーが発生します。
解決策: 堅牢な参照カウント手法
優れたソリューションは参照カウントを利用します。 ディクショナリ内の各セマフォは参照カウントを維持します。 単一のロックにより、カウントのデクリメントとセマフォの削除の原子性が保証され、ConcurrentDictionary
.
<code class="language-csharp">public sealed class AsyncDuplicateLock { private sealed class RefCounted<T> { public RefCounted(T value) { RefCount = 1; Value = value; } public int RefCount { get; set; } public T Value { get; private set; } } private static readonly Dictionary<object, RefCounted<SemaphoreSlim>> SemaphoreSlims = new Dictionary<object, RefCounted<SemaphoreSlim>>(); private SemaphoreSlim GetOrCreate(object key) { RefCounted<SemaphoreSlim> item; lock (SemaphoreSlims) { if (SemaphoreSlims.TryGetValue(key, out item)) { item.RefCount++; } else { item = new RefCounted<SemaphoreSlim>(new SemaphoreSlim(1, 1)); SemaphoreSlims[key] = item; } } return item.Value; } public IDisposable Lock(object key) { GetOrCreate(key).Wait(); return new Releaser { Key = key }; } public async Task<IDisposable> LockAsync(object key) { await GetOrCreate(key).WaitAsync().ConfigureAwait(false); return new Releaser { Key = key }; } private sealed class Releaser : IDisposable { public object Key { get; set; } public void Dispose() { RefCounted<SemaphoreSlim> item; lock (SemaphoreSlims) { item = SemaphoreSlims[Key]; item.RefCount--; if (item.RefCount == 0) SemaphoreSlims.Remove(Key); } item.Value.Release(); } } }</code>
この改訂されたアプローチにより、セマフォが不要になった場合にのみ解放されることが保証され、キャッシュ操作中の断続的なファイル アクセス エラーが効果的に防止されます。
以上がキーに基づく非同期ロックが断続的なファイル アクセス エラーを引き起こすのはなぜですか?また、参照カウントのアプローチでどのように改善できるのでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。