비동기 키 기반 잠금: 간헐적인 파일 액세스 오류의 원인
키 기반 비동기 잠금을 사용하는 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!