我如何以线程安全的方式 (memoryCache) c# GetAsync
How I can GetAsync in a thread safe manner (memoryCache) c#
我正在为 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;
并且您想并行处理这些请求,但使用某种执行不安全调用的方法以 thread-safe 方式进行外部调用。
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);
}
我正在为 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;
并且您想并行处理这些请求,但使用某种执行不安全调用的方法以 thread-safe 方式进行外部调用。
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);
}