问题描述
我正在寻找用于memoryCache的线程安全的“ GetAsync”版本。
我知道有“ GetorCreateAsync”,但是在提交一些数据之前,我需要检查它是否在缓存中。
我一直在谷歌搜索,但是我没有找到即使在有赛车条件的情况下也可以安全使用的ThreadSafe“ GetAsync”方法。
是否有“ GetorCreateAsync”版本,而只是GET?
有什么建议吗?
更新
最后,我使用了如下的GetorAddAsync
private readonly SemaphoreSlim locker = new SemaphoreSlim(1,1);
public async Task<T> GetorAddAsync<T>(object key,Func<ICacheEntry,Task<T>> create)
{
await locker.WaitAsync();
try
{
return await cache.GetorCreateAsync(key,create);
}
finally
{
locker.Release();
}
}
我这样测试过
var tasks = new List<Task>();
var counter = 0;
for (int i = 0; i < 10; i++)
{
var index = i;
tasks.Add(Task.Run(async () =>
{
var x = await cache.GetorAddAsync("test",entry => Task.Fromresult(Interlocked.Increment(ref counter)));
output.WriteLine($"Interaction {index} got {x}");
}));
}
await Task.WhenAll(tasks);
output.WriteLine("Counter {0}",counter);
Assert.True(counter == 1);
}
此测试是否有效,证明可以处理比赛条件?
解决方法
SemaphoreSlim
电动锁。
例如,您有一个只能一次由单个线程访问的方法,例如:
public async Task<MyData> GetDataAsync(string request); // not thread-safe!
一组数据请求,例如
string[] requests;
您想并行处理这些请求,但使用某种执行不安全调用的方法以线程安全的方式进行外部调用。
private async Task MakeRequestAsync(string request,SemaphoreSlim semaphore)
{
await PrepareAsync();
MyData data = null;
await semaphore.WaitAsync(); // begin sync code
try
{
data = await GetDataAsync(request);
}
finally
{
semaphore.Release(); // end sync code
}
if (data != null)
await ProcessResultAsync(data);
}
List<Task> tasks = new List<Task>();
using (SemaphoreSlim semaphore = new SemaphoreSlim(1)) // 1 = concurrency degree
{
foreach (string request in requests)
tasks.Add(MakeRequestAsync(request,semaphore));
await Task.WhenAll(tasks);
}