ASP.NET Web API: 一个很长的方法,如何保证调用一次

ASP.NET Web API: One long method, how to ensure it'll be called once

我有一个很长的 运行 Web 服务请求,完成后应该缓存在服务器端。我的问题是 - 我不知道如何防止它在第一次请求后被缓存之前被调用 concurrently/simultaneously。

我的想法是我应该创建一个数据请求 Task 并将其存储在并发字典中。所以每个其他请求都应该检查 Task 是否已经 运行 并等待它完成。

我已经结束了:

private static ConcurrentDictionary<string, Task> tasksCache = new ConcurrentDictionary<string, Task>();

public static T GetFromCache<T>(this ICacheManager<object> cacheManager, string name, Func<T> func)
{
    if (cacheManager.Exists(name))
        return (T)cacheManager[name];

    if (tasksCache.ContainsKey(name))
    {
        tasksCache[name].Wait();
        return (tasksCache[name] as Task<T>).Result;
    }

    var runningTask = Task.Run(() => func.Invoke());
    tasksCache[name] = runningTask;
    runningTask.Wait();

    var data = runningTask.Result;
    cacheManager.Put(name, data);
    tasksCache.TryRemove(name, out Task t);

    return data;
}

但这看起来很乱。有没有更好的方法?

我会考虑将这些包装在每个任务的 Lazy<T> 中,它具有用于控制并发初始化的内置语义。

This example 演示了如何使用 Lazy<T> class 来提供从多个线程访问的惰性初始化。

您需要指定合适的 LazyThreadSafetyMode

Fully thread safe; uses locking to ensure that only one thread initializes the value. ExecutionAndPublication