Numaralandırma ile ilgili problem
MemoryCache.GetEnumerator () bölümünde Açıklamalar uyarır: ", bir kaynak yoğun ve engelleme işlemini bir MemoryCache örneği için bir sýralayýcý olan alma Bu nedenle, Numaralayıcı üretim uygulamalarında kullanılmamalıdır."
GetEnumerator () uygulamasının sözde kodunda açıklanan nedeni aşağıda açıklanmıştır:
Create a new Dictionary object (let's call it AllCache)
For Each per-processor segment in the cache (one Dictionary object per processor)
{
Lock the segment/Dictionary (using lock construct)
Iterate through the segment/Dictionary and add each name/value pair one-by-one
to the AllCache Dictionary (using references to the original MemoryCacheKey
and MemoryCacheEntry objects)
}
Create and return an enumerator on the AllCache Dictionary
Uygulama, önbelleği birden çok Dictionary nesnesine böldüğünden, bir numaralandırıcıyı geri vermek için her şeyi tek bir koleksiyonda bir araya getirmelidir. GetEnumerator'a yapılan her çağrı, yukarıda ayrıntıları verilen tam kopyalama işlemini yürütür. Yeni oluşturulan Sözlük, orijinal dahili anahtar ve değer nesnelerine referanslar içerir, böylece gerçek önbelleğe alınmış veri değerleriniz çoğaltılmaz.
Belgelerdeki uyarı doğrudur. GetEnumerator () 'dan kaçının - LINQ sorgularını kullanan yukarıdaki tüm yanıtlar dahil.
Daha iyi ve daha esnek bir çözüm
İşte, mevcut değişiklik izleme altyapısını temel alan, önbelleği temizlemenin etkili bir yolu. Ayrıca, önbelleğin tamamını veya yalnızca adlandırılmış bir alt kümeyi temizleme esnekliği sağlar ve yukarıda tartışılan sorunların hiçbirine sahip değildir.
// By Thomas F. Abraham (http://www.tfabraham.com)
namespace CacheTest
{
using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.Caching;
public class SignaledChangeEventArgs : EventArgs
{
public string Name { get; private set; }
public SignaledChangeEventArgs(string name = null) { this.Name = name; }
}
/// <summary>
/// Cache change monitor that allows an app to fire a change notification
/// to all associated cache items.
/// </summary>
public class SignaledChangeMonitor : ChangeMonitor
{
// Shared across all SignaledChangeMonitors in the AppDomain
private static event EventHandler<SignaledChangeEventArgs> Signaled;
private string _name;
private string _uniqueId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
public override string UniqueId
{
get { return _uniqueId; }
}
public SignaledChangeMonitor(string name = null)
{
_name = name;
// Register instance with the shared event
SignaledChangeMonitor.Signaled += OnSignalRaised;
base.InitializationComplete();
}
public static void Signal(string name = null)
{
if (Signaled != null)
{
// Raise shared event to notify all subscribers
Signaled(null, new SignaledChangeEventArgs(name));
}
}
protected override void Dispose(bool disposing)
{
SignaledChangeMonitor.Signaled -= OnSignalRaised;
}
private void OnSignalRaised(object sender, SignaledChangeEventArgs e)
{
if (string.IsNullOrWhiteSpace(e.Name) || string.Compare(e.Name, _name, true) == 0)
{
Debug.WriteLine(
_uniqueId + " notifying cache of change.", "SignaledChangeMonitor");
// Cache objects are obligated to remove entry upon change notification.
base.OnChanged(null);
}
}
}
public static class CacheTester
{
public static void TestCache()
{
MemoryCache cache = MemoryCache.Default;
// Add data to cache
for (int idx = 0; idx < 50; idx++)
{
cache.Add("Key" + idx.ToString(), "Value" + idx.ToString(), GetPolicy(idx));
}
// Flush cached items associated with "NamedData" change monitors
SignaledChangeMonitor.Signal("NamedData");
// Flush all cached items
SignaledChangeMonitor.Signal();
}
private static CacheItemPolicy GetPolicy(int idx)
{
string name = (idx % 2 == 0) ? null : "NamedData";
CacheItemPolicy cip = new CacheItemPolicy();
cip.AbsoluteExpiration = System.DateTimeOffset.UtcNow.AddHours(1);
cip.ChangeMonitors.Add(new SignaledChangeMonitor(name));
return cip;
}
}
}