我正在尝试将下面的方法(简化示例)转换为异步方法,因为
```html
使用
谢谢。
cacheMissResolver
调用可能会花费很长时间(数据库查找、网络调用):```html
我正在尝试将下面的方法(简化示例)转换为异步方法,因为cacheMissResolver
调用可能会花费很长时间(数据库查找、网络调用):
// 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;
}
}
网上有很多关于使用异步方法的资料,但是我发现关于编写异步方法的建议似乎不够清晰。考虑到这是一个库的一部分,下面的尝试哪一个是正确的呢?
// 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
在异步方法中替换锁语句是正确的吗?(我无法在锁语句的主体中使用await。)
cacheMissResolver
参数应该改为Func<Task<Thing>>
类型吗?虽然这会让调用者承担确保解析程序函数是异步的负担(包装在Task.Run
中),但如果需要很长时间,它将被卸载到后台线程。谢谢。
AsyncLock
。 - Timothy ShieldsConcurrentDictionary
。 - Servy