我如何以线程安全的方式获取GetAsyncmemoryCachec#

问题描述

我正在寻找用于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);
}