gpt4 book ai didi

wcf - 在异步服务中缓存

转载 作者:行者123 更新时间:2023-12-05 01:11:56 25 4
gpt4 key购买 nike

所以,我遇到了一个有趣的情况。假设我有一组很少更改的数据,所以我不想在每次调用大容量服务时都获取它。我通常会将此数据缓存一段时间(取决于实际更改的频率)。这非常简单:

private T GetOrSet<T>(string key, Func<T> getToSet, int minutes, object lockObject)
{
T value = (T)HttpRuntime.Cache.Get(key);
if (value == null)
{
lock (lockObject)
{
value = (T)HttpRuntime.Cache.Get(key);
if (value == null)
{
value = getToSet();
HttpRuntime.Cache.Insert(key, value, null, DateTime.UtcNow.AddMinutes(minutes), Cache.NoSlidingExpiration);
}
}
}
return value;
}

如果getToSet函数失败,我从不插入,因此在下一次调用时再次尝试。

但是,如果我在异步服务中使用相同的模式,getToSet函数返回 Task<> - 现在我缓存了一个 Task在一段时间内返回失败的结果。假设时间调用getToSet不可忽略,如何在数据检索期间不阻塞线程的情况下防止缓存失败的结果?

下面是简短但完整的示例;这会将失败的结果缓存一分钟,在此期间每次调用 GetData将失败,然后服务将开始返回 5每次通话。

using System;
using System.ServiceModel;
using System.Threading.Tasks;
using System.Web;
using System.Web.Caching;

namespace TaskCacheIssue
{
[ServiceContract]
public interface IService1
{
[OperationContract]
Task<int> GetData();
}

public class Service1 : IService1
{

public async Task<int> GetData()
{
return await GetDataFromCache();
}

private static bool first = true;
private static readonly object deadbolt = new object();
private async Task<int> GetDataFromCache()
{
return await GetOrSet(
"key",
async () => await GetDataFromSomewhereElse(),
1,
deadbolt);
}

private async Task<int> GetDataFromSomewhereElse()
{
// This is actually a longer-running data retrieval.
if (first)
{
first = false;
throw new Exception("FIRST!");
}
return 5;
}

private T GetOrSet<T>(string key, Func<T> getToSet, int minutes, object lockObject)
{
T value = (T)HttpRuntime.Cache.Get(key);
if (value == null)
{
lock (lockObject)
{
value = (T)HttpRuntime.Cache.Get(key);
if (value == null)
{
value = getToSet();
HttpRuntime.Cache.Insert(key, value, null, DateTime.UtcNow.AddMinutes(minutes), Cache.NoSlidingExpiration);
}
}
}
return value;
}

}
}

最佳答案

不是专门评估 null,而是额外检查缓存值是否是失败的任务。

private T GetOrSet<T>(string key, Func<T> getToSet, int minutes, object lockObject)
{
T value = (T)HttpRuntime.Cache.Get(key);
if (value == null || IsCanceledOrFaultedTask(value))
{
lock (lockObject)
{
value = (T)HttpRuntime.Cache.Get(key);
if (value == null || IsCanceledOrFaultedTask(value))
{
value = getToSet();
HttpRuntime.Cache.Insert(key, value, null, DateTime.UtcNow.AddMinutes(minutes), Cache.NoSlidingExpiration);
}
}
}
return value;
}

private bool IsCanceledOrFaultedTask(object target)
{
if (target is Task)
{
var task = (Task)target;
return (task.IsCanceled || task.IsFaulted);
}

return false;
}

关于wcf - 在异步服务中缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29541927/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com