Нужна помощь в профилировании .NET метода кэширования - PullRequest
0 голосов
/ 03 января 2011

У меня есть следующее расширение

Public Module CacheExtensions
    Sub New()
    End Sub

    Private sync As New Object()
    Public Const DefaultCacheExpiration As Integer = 1200 ''# 20 minutes

    <Extension()> 
    Public Function GetOrStore(Of T)(ByVal cache As Cache, ByVal key As String, ByVal generator As Func(Of T)) As T
        Return cache.GetOrStore(key, If(generator IsNot Nothing, generator(), Nothing), DefaultCacheExpiration)
    End Function

    <Extension()> 
    Public Function GetOrStore(Of T)(ByVal cache As Cache, ByVal key As String, ByVal generator As Func(Of T), ByVal expireInSeconds As Double) As T
        Return cache.GetOrStore(key, If(generator IsNot Nothing, generator(), Nothing), expireInSeconds)
    End Function

    <Extension()> 
    Public Function GetOrStore(Of T)(ByVal cache As Cache, ByVal key As String, ByVal obj As T) As T
        Return cache.GetOrStore(key, obj, DefaultCacheExpiration)
    End Function

    <Extension()> 
    Public Function GetOrStore(Of T)(ByVal cache As Cache, ByVal key As String, ByVal obj As T, ByVal expireInSeconds As Double) As T
        Dim result = cache(key)

        If result Is Nothing Then

            SyncLock sync
                If result Is Nothing Then
                    result = If(obj IsNot Nothing, obj, Nothing)
                    cache.Insert(key, result, Nothing, DateTime.Now.AddSeconds(expireInSeconds), cache.NoSlidingExpiration)
                End If
            End SyncLock
        End If

        Return DirectCast(result, T)

    End Function

End Module

Здесь я использую расширение TagService для получения списка тегов

    Public Function GetTagNames() As List(Of String) Implements Domain.ITagService.GetTags
        ''# We're not using a dynamic Cache key because the list of TagNames
        ''# will persist across all users in all regions.
        Return HttpRuntime.Cache.GetOrStore(Of List(Of String))("TagNamesOnly",
                                                                Function() _TagRepository.Read().Select(Function(t) t.Name).OrderBy(Function(t) t).ToList())
    End Function

Все этов значительной степени прямо вперед, за исключением случаев, когда я ставлю точку останова на _TagRepository.Read().Проблема в том, что он вызывается при каждом запросе, когда я думал, что он вызывается только тогда, когда Result Is Nothing

Я что-то здесь упускаю?

РЕДАКТИРОВАТЬ: и для вас ребята, вот эквивалент C #

public static class CacheExtensions
{

    private static object sync = new object();
    public const int DefaultCacheExpiration = 20;

    public static T GetOrStore<T>( this Cache cache, string key, Func<T> generator ) {
        return cache.GetOrStore( key, generator != null ? generator() : default( T ), DefaultCacheExpiration );
    }

    public static T GetOrStore<T>( this Cache cache, string key, Func<T> generator, double expireInMinutes ) {
        return cache.GetOrStore( key, generator != null ? generator() : default( T ), expireInMinutes );
    }

    public static T GetOrStore<T>( this Cache cache, string key, T obj ) {
        return cache.GetOrStore( key, obj, DefaultCacheExpiration );
    }

    public static T GetOrStore<T>( this Cache cache, string key, T obj, double expireInMinutes ) {
        var result = cache[key];

        if ( result == null ) {

            lock ( sync ) {
                if ( result == null ) {
                    result = obj != null ? obj : default( T );
                    cache.Insert( key, result, null, DateTime.Now.AddMinutes( expireInMinutes ), Cache.NoSlidingExpiration );
                }
            }
        }

        return (T)result;

    }

}

и вызов

    return HttpRuntime.Cache.GetOrStore<List<string>>("TagNamesOnly", () => _TagRepository.Read().Select(t => t.Name).OrderBy(t => t).ToList());

Ответы [ 2 ]

1 голос
/ 03 января 2011

Проблема в том, что вы вызываете перегруженный метод, который вызывает ваш метод, и, как @Simon Svensson указал, что метод, который вы вызываете, не тот метод, который вы опубликовали. Это версия C # метода, который вы на самом деле вызываете:

return cache.GetOrStore( key, generator != null ? generator() : default( T ), DefaultCacheExpiration )

Сразу же вы увидите, что второй аргумент вызывает generator(), если ему передано ненулевое значение.

ОБНОВЛЕНО

Проблема не связана с кэшированием, а в том, что перегруженный метод, который вы вызываете, выполняет ваш лямбда-метод. Если вы действительно настроены на вызов метода, как вы обрисовали в общих чертах, вам придется изменить его на что-то вроде этого:

''# Fix StackOverflow Code Coloring Bug     
<Extension()>
Public Function GetOrStore(Of T)(ByVal cache As Cache, ByVal key As String, ByVal generator As Func(Of T)) As T
    ''# Null value to pass to first call. We can not use Nothing because VB can not infer the overload type
    Dim NV As Object = Nothing
    ''# Call the primary method passing a null value
    Dim Ret = cache.GetOrStore(key, NV, DefaultCacheExpiration)
    ''# If that call returns nothing call our generator() method and then re-call the main method
    If (Ret Is Nothing) AndAlso (generator IsNot Nothing) Then
        Ret = cache.GetOrStore(key, generator(), DefaultCacheExpiration)
    End If
    Return Ret
End Function

Я не проверял это, но это или что-то очень близкое должно дать вам то, что вы хотите. Это также, почему я не большой поклонник лямбд. Идея замечательная, но люди, как правило, объединяют так много людей и создают код, который на самом деле не читается. Я предпочел бы иметь 10 строк, которые я могу прочитать, чем 1 строку, которая делает то же самое.

1 голос
/ 03 января 2011

Подпись GetOrStore и его реализация не содержат оценки функции, которую вы отправляете. Я действительно не знаю, что происходит в данный момент (или действительно ли это работает).Кажется, вы добавляете Func в свой кэш.

public const int DefaultCacheExpiration = 20;
private static readonly Object SyncRoot = new Object();
public static T GetOrStore<T>(this Cache cache, String key, Func<T> itemGenerator, Double expireInSeconds = DefaultCacheExpiration) {
    var item = cache[key];
    if (item != null)
        return (T)item;

    lock (SyncRoot) {
        // Fetch a second time to check if anyone have
        // added it while we blocked waiting for the lock.
        item = cache[key];
        if (item != null)
            return (T)item;

        // Invoke the almighty itemGenerator to execute,
        // and generate, the item that should be inserted
        // into the cache.
        item = itemGenerator.Invoke();
        cache.Insert(key, item, null, DateTime.Now.AddSeconds(expireInSeconds), Cache.NoSlidingExpiration);
        return (T)item;
    }
}

public static T GetOrStore<T>(this Cache cache, String key, T newItem, Double expireInSeconds = DefaultCacheExpiration) {
    return cache.GetOrStore(key, () => newItem, expireInSeconds);
}

Если этого не происходит, посмотрите настройки кэширования asp.net и объем свободной памяти на сервере.Кеш не работает в условиях нехватки памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...