Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 用于获取集合的缓存模式_C#_Performance_Caching_Design Patterns_Async Await - Fatal编程技术网

C# 用于获取集合的缓存模式

C# 用于获取集合的缓存模式,c#,performance,caching,design-patterns,async-await,C#,Performance,Caching,Design Patterns,Async Await,是否有一种缓存策略/模式可用于获取多个项目,其中只能缓存一些项目?在这种情况下使用缓存有意义吗 更多细节 其中缓存将返回单个(或已知数量的)结果缓存的简单;如果它在缓存中,我们将返回它,如果不是,我们将获取它,将它添加到缓存中,然后返回它: //using System.Runtime.Caching; ObjectCache cache = MemoryCache.Default; TimeSpan cacheLifetime = new TimeSpan(0, 20, 0); SomeObj

是否有一种缓存策略/模式可用于获取多个项目,其中只能缓存一些项目?在这种情况下使用缓存有意义吗

更多细节

其中缓存将返回单个(或已知数量的)结果缓存的简单;如果它在缓存中,我们将返回它,如果不是,我们将获取它,将它添加到缓存中,然后返回它:

//using System.Runtime.Caching;
ObjectCache cache = MemoryCache.Default;
TimeSpan cacheLifetime = new TimeSpan(0, 20, 0);
SomeObjectFinder source = new SomeObjectFinder();
public SomeObject GetById(long id)
{
    return GetFromCacheById(id) ?? GetFromSourceById(id);
}
protected SomeObject GetFromCacheById(long id)
{
    return (SomeObject)cache.Get(id.ToString(),null);
}
protected SomeObject GetFromSourceById (long id)
{
    SomeObject result = source.GetById(id);
    return result == null ? null : (SomeObject)cache.AddOrGetExisting(id.ToString(), result, DateTimeOffset.UtcNow.Add(cacheLifetime), null);
}
然而,如果我们不知道预期会有多少结果,那么如果我们从缓存中获取结果,我们就不会知道我们已经获取了所有结果;只有缓存的内容。因此,按照上述模式,如果没有缓存任何或所有结果,我们就可以了;但如果他们中有一半是,我们会得到部分结果集

我在想下面的话可能有道理;但是我以前没有玩过
async
/
await
,我读过的大部分内容表明,从同步代码调用异步代码通常被认为是不好的;所以这个解决方案可能不是个好主意

public IEnumerable<SomeObject> GetByPartialName(string startOfName)
{
    //kick off call to the DB (or whatever) to get the full result set 
    var getResultsTask = Task.Run<IList<SomeObject>>(async() => await GetFromSourceByPartialNameAsync(startOfName));
    //whilst we leave that to run in the background, start getting and returning the results from the cache
    var cacheResults = GetFromCacheByPartialName(startOfName);
    foreach (var result in cacheResults)
    {
        yield return result;
    }
    //once all cached values are returned, wait for the async task to complete, remove the results we'd already returned from cache, then add the remaining results to cache and return those also
    var results = getResultsTask.GetAwaiter().GetResult();
    foreach (var result in results.Except(cacheResults))
    {
        yield return CacheAddOrGetExistingByName(result.Name, result);
    }
}
protected async Task<IList<SomeObject>> GetFromSourceByPartialNameAsync(string startOfName)
{
    return source.GetByPartialName(startOfName);
}
public IEnumerable GetByPartialName(字符串startOfName)
{
//启动对DB(或其他)的调用,以获得完整的结果集
var getResultsTask=Task.Run(async()=>Wait GetFromSourceByPartialNameAsync(startOfName));
//当我们让它在后台运行时,开始从缓存中获取并返回结果
var cacheResults=GetFromCacheByPartialName(startOfName);
foreach(cacheResults中的var结果)
{
收益结果;
}
//返回所有缓存的值后,等待异步任务完成,删除我们已经从缓存返回的结果,然后将其余结果添加到缓存中,并同时返回这些结果
var results=getResultsTask.GetAwaiter().GetResult();
foreach(结果中的var结果。除了(cacheResults))
{
返回CacheAddOrGetExistingByName(result.Name,result);
}
}
受保护的异步任务GetFromSourceByPartialNameAsync(字符串startOfName)
{
返回source.GetByPartialName(startOfName);
}

我的假设是,答案将是“在这种情况下,要么预先缓存所有内容,要么不使用缓存”。。。但希望有更好的选择。

您可以使用Decorator和strategy模式,这里是指向的链接,对于单个项目也可以使用,因此您可以使用redis使用Decorator,如果找不到它,它将进入数据库,然后保存到数据库,之后查询数据将非常快

以下是一些示例代码:

public class CachedAlbumRepository : IAlbumRepository
{
    private readonly IAlbumRepository _albumRepository;

public CachedAlbumRepository(IAlbumRepository albumRepository)
{
    _albumRepository = albumRepository;
}

private static readonly object CacheLockObject = new object();

public IEnumerable<Album> GetTopSellingAlbums(int count)
{
    Debug.Print("CachedAlbumRepository:GetTopSellingAlbums");
    string cacheKey = "TopSellingAlbums-" + count;
    var result = HttpRuntime.Cache[cacheKey] as List<Album>;
    if (result == null)
    {
        lock (CacheLockObject)
        {
            result = HttpRuntime.Cache[cacheKey] as List<Album>;
    if (result == null)
            {
                result = _albumRepository.GetTopSellingAlbums(count).ToList();
                HttpRuntime.Cache.Insert(cacheKey, result, null, 
                    DateTime.Now.AddSeconds(60), TimeSpan.Zero);
            }
        }
    }
    return result;
}
}
公共类CachedAlbumRepository:IAlbumRepository
{
专用只读存储库\u albumRepository;
公共缓存数据库存储库(IAlbumRepository albumRepository)
{
_albumRepository=albumRepository;
}
私有静态只读对象CacheLockObject=新对象();
公共IEnumerable GetTopSellingAlbums(整数计数)
{
Print(“CachedAlbumRepository:GetTopSellingAlbums”);
字符串cacheKey=“TopSellingAlbums-”+计数;
var result=HttpRuntime.Cache[cacheKey]作为列表;
如果(结果==null)
{
锁(CacheLockObject)
{
结果=HttpRuntime.Cache[cacheKey]作为列表;
如果(结果==null)
{
结果=_albumRepository.GetTopSellingAlbums(count.ToList();
HttpRuntime.Cache.Insert(cacheKey,result,null,
DateTime.Now.AddSeconds(60),TimeSpan.Zero);
}
}
}
返回结果;
}
}

如果每次都要去(相对较慢的)源代码进行检查,那么该集合类型可能不适合缓存?我认为异步在这里帮不了你多少忙——异步调用并不比同步调用快——实际上稍微慢一点;你只需要在等待它完成的同时做其他事情。因此,在返回调用方之前,您仍然需要等待更长的时间来获取缓存项并返回它们;这符合我的假设。上面的好处是,当我们返回
IEnumerable
时,在获取结果后要进行的任何处理都可以开始循环通过第一个(缓存的)值,而其他值仍在获取中;但我同意,这一点的任何好处都可能在极端边缘情况之外增加的复杂性中丢失。@JohnLBevan:请注意,
IEnumerable
返回值可能会导致对该方法的多次调用,这反过来可能会导致有时不希望出现的结果(例如,集合值不断变化)。如果不包含这些行为,最好返回
IList
。关于缓存,我发现只要都在内存中,
IDictionary
就具有很高的性能。如果需要持久化,SQLite非常快。