itsource

시스템을 지우는 방법런타임.캐싱.메모리 캐시

mycopycode 2023. 9. 4. 19:46
반응형

시스템을 지우는 방법런타임.캐싱.메모리 캐시

사용합니다.System.Runtime.Caching.MemoryCache만료되지 않는 항목을 보유합니다.그러나 경우에 따라 전체 캐시를 지우는 기능이 필요합니다.그걸 어떻게 하는 거죠?

캐시를 열거할 수 있는지 여부에 대해 여기서 비슷한 질문을 했지만, 열거하는 동안 동기화해야 하기 때문에 좋지 않은 생각입니다.

사용해 보았습니다..Trim(100)하지만 그것은 전혀 효과가 없습니다.

린크를 통해 모든 키의 목록을 얻으려고 노력했지만, 아이템을 하나씩 제거하면 쉽게 레이스 상태로 이어질 수 있기 때문에 처음 시작했던 곳으로 돌아왔습니다.

나는 모든 열쇠를 보관하고, 그리고 나서 발행하려고 생각했습니다..Remove(key)각각의 경우, 하지만 거기에도 잠재적인 인종 조건이 있기 때문에 키 목록에 대한 액세스 권한을 잠가야 합니다. 그러면 일이 다시 복잡해집니다.

그리고 나서 저는 제가 전화를 할 수 있어야 한다고 생각했습니다..Dispose()전체 캐시에서 사용할 수 있지만, 구현 방식 때문에 이 방법이 최선인지는 잘 모르겠습니다.

용사를 합니다.ChangeMonitors이는 제 설계에 대한 옵션이 아니며, 이러한 사소한 요구사항에 대해 불필요하게 복잡합니다.

캐시를 완전히 지우는 방법은 무엇입니까?

저는 처음에 이것 때문에 어려움을 겪었습니다.메모리 캐시.체납.트림(100)이 작동하지 않습니다(설명한 대로).트리밍은 최선의 시도이므로 캐시에 100개의 항목이 있고 트리밍(100)을 호출하면 가장 적게 사용되는 항목이 제거됩니다.

자르기는 제거된 항목의 개수를 반환하며 대부분의 사용자는 제거된 항목이 모두 제거될 것으로 예상합니다.

이 코드는 메모리 캐시를 사용한 xUnit 테스트에서 메모리 캐시의 모든 항목을 제거합니다.체납.메모리 캐시.기본값은 기본 영역입니다.

foreach (var element in MemoryCache.Default)
{
    MemoryCache.Default.Remove(element.Key);
}

더 이상 메모리 캐시를 사용할 수 있으려면 메모리 캐시의 기본 멤버를 폐기하지 마십시오.

캐시 상태는 캐시가 삭제되었음을 나타내도록 설정됩니다.캐시 항목을 추가, 제거 또는 검색하는 방법과 같이 캐시 상태를 변경하는 공용 캐시 메서드를 호출하려고 하면 예기치 않은 동작이 발생할 수 있습니다.예를 들어 캐시가 삭제된 후 Set 메서드를 호출하면 no-op 오류가 발생합니다.캐시에서 항목을 검색하려고 하면 Get 메서드는 항상 Nothing을 반환합니다.http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.dispose.aspx

트림에 대해서는 다음과 같이 작동해야 합니다.

트림 속성은 먼저 절대 만료 또는 슬라이딩 만료를 초과한 항목을 제거합니다.제거된 항목에 대해 등록된 콜백은 제거된 Expired 사유를 통과합니다.

만료된 항목을 제거해도 지정된 트림 백분율에 도달하기에 충분하지 않으면 요청된 트림 백분율에 도달할 때까지 가장 최근에 사용된(LRU) 알고리즘에 따라 캐시에서 추가 항목이 제거됩니다.

하지만 다른 두 명의 사용자가 같은 페이지에서 작동하지 않는다고 보고했기 때문에 제거() http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.trim.aspx 를 고수하고 있는 것 같습니다.

업데이트 그러나 싱글톤이거나 여러 인스턴스를 사용하는 것이 안전하지 않다는 언급이 없으므로 참조를 덮어쓸 수 있습니다.

그러나 기본 인스턴스에서 메모리를 해제해야 하는 경우 수동으로 삭제하거나 폐기(사용할 수 없게 함)를 통해 영구적으로 삭제해야 합니다.

당신의 질문에 기초하여 당신은 내부적으로 마음대로 처분할 수 있는 메모리 캐시를 반환하는 당신만의 싱글톤 부과 클래스를 만들 수 있습니다.캐시의 본질이 되는 것 :-)

여기 제가 작업하던 것을 위해 만든 것이 있습니다.

public void Flush()
{
    List<string> cacheKeys = MemoryCache.Default.Select(kvp => kvp.Key).ToList();
    foreach (string cacheKey in cacheKeys)
    {
        MemoryCache.Default.Remove(cacheKey);
    }
}

이것이 오래된 질문이라는 것을 알지만 내가 발견한 가장 좋은 선택은

기존 메모리 캐시를 폐기하고 새 메모리 캐시 개체를 만듭니다.https://stackoverflow.com/a/4183319/880642

스레드 안전한 방법으로 이 작업을 수행할 수 있는 코드를 제공하지 않습니다.그러나 인터록을 사용하면 이 작업을 수행할 수 있습니다.교환

var oldCache = Interlocked.Exchange(ref _existingCache, new MemoryCache("newCacheName"));
oldCache.Dispose();

이렇게 하면 기존 캐시를 새 캐시로 교체하고 원래 캐시에서 안전하게 Dispose를 호출할 수 있습니다.이렇게 하면 캐시가 사용 중인 동안 캐시를 폐기할 때 발생하는 캐시 및 레이스 조건의 항목을 열거할 필요가 없습니다.


편집

DI에 대한 실제 회계에서 사용하는 방법은 다음과 같습니다.

public class CustomCacheProvider : ICustomCacheProvider
{
    private IMemoryCache _internalCache;
    private readonly ICacheFactory _cacheFactory;

    public CustomCacheProvider (ICacheFactory cacheFactory)
    {
        _cacheFactory = cacheFactory;
        _internalCache = _cacheFactory.CreateInstance();
    }
    public void Set(string key, object item, MemoryCacheEntryOptions policy)
    {
        _internalCache.Set(key, item, policy);
    }

    public object Get(string key)
    {
        return _internalCache.Get(key);
    }
   // other methods ignored for breviy 

    public void Dispose()
    {
        _internalCache?.Dispose();
    }

    public void EmptyCache()
    {
        var oldCache = Interlocked.Exchange(ref _internalCache, _cacheFactory.CreateInstance());
        oldCache.Dispose();
    }
}

중요한 것은 공장을 사용하여(또는 원하는 경우 수동으로) 새 캐시 인스턴스를 생성할 수 있는 다른 싱글톤을 사용하여 내부 캐시에 대한 액세스를 제어하는 것입니다.

@stefan의 답변에 있는 세부 사항은 원칙을 자세히 설명합니다; 제가 어떻게 해야 하는지에 대해 말씀드리겠습니다.

클라이언트 코드가 폐기된 후 다시 생성되기 전에 캐시에 액세스하는 경쟁 상태를 방지하려면 캐시를 재생성하는 동안 캐시에 대한 액세스를 동기화해야 합니다.

이 동기화를 방지하려면 메모리 캐시를 감싸는 어댑터 클래스에서 다음 작업을 수행합니다.

public void clearCache() {
  var oldCache = TheCache;
  TheCache = new MemoryCache("NewCacheName", ...);
  oldCache.Dispose();
  GC.Collect();
}

이쪽입니다.TheCache는 항상 동기화되지 않은 상태이며 동기화가 필요하지 않습니다.

저도 이 문제에 부딪혔습니다. .Disposure()는 제가 예상했던 것과 상당히 다른 일을 했습니다.

대신 컨트롤러 클래스에 정적 필드를 추가했습니다.이 동작을 피하기 위해 기본 캐시를 사용하지 않고 개인 캐시를 만들었습니다.그래서 제가 구현한 것은 다음과 같습니다.

public class MyController : Controller
{

    static MemoryCache s_cache = new MemoryCache("myCache");

    public ActionResult Index()
    {

        if (conditionThatInvalidatesCache)
        {
            s_cache = new MemoryCache("myCache");
        }

        String s = s_cache["key"] as String;

        if (s == null)
        {
            //do work
            //add to s_cache["key"]
        }

        //do whatever next
    }
}

이 게시물, 구체적으로 토마스 F.의 답변을 확인하십시오. 에이브러햄이 올렸습니다.전체 캐시 또는 명명된 하위 집합을 지울 수 있는 솔루션이 있습니다.

여기서 중요한 것은 다음과 같습니다.

// Cache objects are obligated to remove entry upon change notification.
base.OnChanged(null);

제가 직접 구현해 본 결과, 모든 것이 잘 작동하는 것 같아요.

언급URL : https://stackoverflow.com/questions/8043381/how-do-i-clear-a-system-runtime-caching-memorycache

반응형