我如何以线程安全的方式 (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);
}