ฉันได้สร้างแคชโดยใช้คลาส MemoryCache ฉันเพิ่มบางรายการเข้าไป แต่เมื่อฉันต้องการโหลดแคชใหม่ฉันต้องการล้างมันก่อน อะไรคือวิธีที่เร็วที่สุดในการดำเนินการนี้ ฉันควรวนซ้ำรายการทั้งหมดและลบทีละรายการหรือมีวิธีที่ดีกว่านี้
ฉันได้สร้างแคชโดยใช้คลาส MemoryCache ฉันเพิ่มบางรายการเข้าไป แต่เมื่อฉันต้องการโหลดแคชใหม่ฉันต้องการล้างมันก่อน อะไรคือวิธีที่เร็วที่สุดในการดำเนินการนี้ ฉันควรวนซ้ำรายการทั้งหมดและลบทีละรายการหรือมีวิธีที่ดีกว่านี้
คำตอบ:
Dispose
MemoryCache ที่มีอยู่และสร้างวัตถุ MemoryCache ใหม่
Dispose
จะกล่าวถึงที่เรียกสิ่งที่CacheEntryRemovedCallback
แนบมากับรายการแคชปัจจุบัน
ส่วนMemoryCache.GetEnumerator () หมายเหตุเตือน: "การเรียกตัวแจงนับสำหรับอินสแตนซ์ MemoryCache เป็นการดำเนินการที่ใช้ทรัพยากรมากและปิดกั้นดังนั้นจึงไม่ควรใช้ตัวแจงนับในแอปพลิเคชันการผลิต"
นี่คือเหตุผลที่อธิบายในรหัสเทียมของการใช้งาน GetEnumerator ():
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
เนื่องจากการใช้งานจะแยกแคชออกจากออบเจ็กต์พจนานุกรมหลายรายการจึงต้องรวมทุกอย่างเข้าด้วยกันเป็นคอลเลกชั่นเดียวเพื่อส่งตัวนับคืน การเรียกใช้ GetEnumerator ทุกครั้งจะดำเนินการตามขั้นตอนการคัดลอกทั้งหมดตามรายละเอียดด้านบน พจนานุกรมที่สร้างขึ้นใหม่มีการอ้างอิงถึงคีย์ภายในดั้งเดิมและอ็อบเจ็กต์ค่าดังนั้นค่าข้อมูลแคชจริงของคุณจะไม่ซ้ำกัน
คำเตือนในเอกสารถูกต้อง หลีกเลี่ยง GetEnumerator () - รวมถึงคำตอบทั้งหมดข้างต้นที่ใช้แบบสอบถาม LINQ
นี่เป็นวิธีที่มีประสิทธิภาพในการล้างแคชที่สร้างขึ้นจากโครงสร้างพื้นฐานการตรวจสอบการเปลี่ยนแปลงที่มีอยู่ นอกจากนี้ยังให้ความยืดหยุ่นในการล้างแคชทั้งหมดหรือเฉพาะส่วนย่อยที่มีชื่อและไม่มีปัญหาใด ๆ ที่กล่าวถึงข้างต้น
// 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;
}
}
}
วิธีแก้ปัญหาคือ:
List<string> cacheKeys = MemoryCache.Default.Select(kvp => kvp.Key).ToList();
foreach (string cacheKey in cacheKeys)
{
MemoryCache.Default.Remove(cacheKey);
}
Select()
?
var cacheItems = cache.ToList();
foreach (KeyValuePair<String, Object> a in cacheItems)
{
cache.Remove(a.Key);
}
หากประสิทธิภาพไม่ใช่ปัญหาหนึ่งซับที่ดีนี้จะทำเคล็ดลับ:
cache.ToList().ForEach(a => cache.Remove(a.Key));
ดูเหมือนว่าจะมีวิธีการตัดแต่ง
เพื่อล้างเนื้อหาทั้งหมดที่คุณเพิ่งทำ
cache.Trim(100)
แก้ไข: หลังจากขุดเพิ่มเติมดูเหมือนว่าการดู Trim จะไม่คุ้มค่ากับเวลาของคุณ
คุณสามารถทำสิ่งนี้ได้:
Dim _Qry = (From n In CacheObject.AsParallel()
Select n).ToList()
For Each i In _Qry
CacheObject.Remove(i.Key)
Next
วิ่งข้ามสิ่งนี้และจากนั้นเขียนวิธีการล้างแบบขนานที่มีประสิทธิภาพมากกว่าเล็กน้อย:
public void ClearAll()
{
var allKeys = _cache.Select(o => o.Key);
Parallel.ForEach(allKeys, key => _cache.Remove(key));
}
ฉันสนใจแค่การล้างแคชและพบว่านี่เป็นตัวเลือกเมื่อใช้ c # GlobalCachingProvider
var cache = GlobalCachingProvider.Instance.GetAllItems();
if (dbOperation.SuccessLoadingAllCacheToDB(cache))
{
cache.Clear();
}
คำตอบ magritte รุ่นปรับปรุงเล็กน้อย
var cacheKeys = MemoryCache.Default.Where(kvp.Value is MyType).Select(kvp => kvp.Key).ToList();
foreach (string cacheKey in cacheKeys)
{
MemoryCache.Default.Remove(cacheKey);
}
คุณสามารถกำจัด MemoryCache แคชดีฟอลต์แล้วตั้งค่าไพรเวตฟิลด์ singleton ใหม่เป็น null เพื่อสร้าง MemoryCache ใหม่
var field = typeof(MemoryCache).GetField("s_defaultCache",
BindingFlags.Static |
BindingFlags.NonPublic);
field.SetValue(null, null);