I am trying to convert the following method (simplified example) to asynchronous, since calling cacheMissResolver can be costly in terms of time (database search, network call):
// Synchronous version public class ThingCache { private static readonly object _lockObj; // ... other stuff public Thing Get(string key, Func<Thing> cacheMissResolver) { if (cache.Contains(key)) return cache[key]; Thing item; lock(_lockObj) { if (cache.Contains(key)) return cache[key]; item = cacheMissResolver(); cache.Add(key, item); } return item; } }
There is a lot of material on the Internet about consuming asynchronous methods, but the tips I found when creating them seem less clear. Given that this is intended to be part of the library, are my attempts below correct?
// Asynchronous attempts public class ThingCache { private static readonly SemaphoreSlim _lockObj = new SemaphoreSlim(1); // ... other stuff // attempt #1 public async Task<Thing> Get(string key, Func<Thing> cacheMissResolver) { if (cache.Contains(key)) return await Task.FromResult(cache[key]); Thing item; await _lockObj.WaitAsync(); try { if (cache.Contains(key)) return await Task.FromResult(cache[key]); item = await Task.Run(cacheMissResolver).ConfigureAwait(false); _cache.Add(key, item); } finally { _lockObj.Release(); } return item; } // attempt #2 public async Task<Thing> Get(string key, Func<Task<Thing>> cacheMissResolver) { if (cache.Contains(key)) return await Task.FromResult(cache[key]); Thing item; await _lockObj.WaitAsync(); try { if (cache.Contains(key)) return await Task.FromResult(cache[key]); item = await cacheMissResolver().ConfigureAwait(false); _cache.Add(key, item); } finally { _lockObj.Release(); } return item; } }
SemaphoreSlim use the correct way to replace the lock statement with the async method? (I cannot wait for the lock statement in the body.)
Should I make a cacheMissResolver argument of type Func<Task<Thing>> ? Although it is the responsibility of the resolver async function to Task.Run call (wrapping in Task.Run , I know that it will be unloaded into the background thread if it takes a long time).
Thanks.
c # asynchronous async-await
rob
source share