C#在缓存中存储值类型

时间:2016-10-31 14:38:34

标签: c# caching value-type reference-type

问题

给定一个返回网站上活跃用户总数的函数:

private static readonly object Lock = new object();
public static int GetTotalActiveUsers()
{
    var cache = HttpContext.Current.Cache;
    if (cache["ActiveUsers"] == null)
    {
        lock (Lock)
        {
            if (cache["ActiveUsers"] == null)
            {
                var activeUsers = 5; // This would actually be an expensive operation
                cache.Add("ActiveUsers", activeUsers, null, Cache.NoAbsoluteExpiration,
                    Cache.NoSlidingExpiration,
                    CacheItemPriority.Normal, null);
            }
        }
    }
    return (int) cache["ActiveUsers"];
}

以这种方式将ValueType存储在缓存中的问题是它不可更新。例如:

public static void OnNewActiveUser()
{
    var total = GetTotalActiveUsers();
    total++;
}

不更新缓存的值。 (这是预期的行为)。

我正在寻找一种更新活动用户数的线程安全方法。

解决方案1 ​​

使用锁

public static void OnNewActiveUser()
{
    lock (UpdateActiveUsersLock)
    {
        var cache = HttpContext.Current.Cache;
        var newTotal = GetTotalActiveUsers() + 1;
        cache.Insert("ActiveUsers", newTotal, null, Cache.NoAbsoluteExpiration,
                    Cache.NoSlidingExpiration,
                    CacheItemPriority.Normal, null);
    }
}

解决方案2

在int周围创建一个瘦类,将其转换为引用类型:

public class CachedInt
{
    public int Int { get; set; }
    public CachedInt(int value)
    {
        Int = value;
    }
}

然后:

public static void OnNewActiveUser()
{
    var activeUsers = GetTotalActiveUsers();
    activeUsers.Int++;
}

问题

如果可能的话,我更愿意避免解决方案1(它并不适合我的设计)。将值类型包装在一个很薄的类代码中,或者它是解决问题的合法方法吗?

1 个答案:

答案 0 :(得分:1)

HttpContext.Current.Cache缓存对象(引用类型),因此您需要按照建议将int(值类型)包装为引用类型。

为什么如果缓存的项目永不过期,为什么不仅仅拥有一个带有静态方法和静态成员的类来计数呢?

此外,您应该使用互锁递增以确保计数正确,并具有某种方式来了解用户何时处于非活动状态,以便可以递减计数。正如评论中指出的那样,这只会为您提供单个进程的计数。如果您在同一台计算机上有多个Web进程或多个服务器,则计数将是错误的-也许这就是返回5的昂贵操作:)