给定一个返回网站上活跃用户总数的函数:
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++;
}
不更新缓存的值。 (这是预期的行为)。
我正在寻找一种更新活动用户数的线程安全方法。
使用锁
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);
}
}
在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(它并不适合我的设计)。将值类型包装在一个很薄的类代码中,或者它是解决问题的合法方法吗?
答案 0 :(得分:1)
HttpContext.Current.Cache
缓存对象(引用类型),因此您需要按照建议将int(值类型)包装为引用类型。
为什么如果缓存的项目永不过期,为什么不仅仅拥有一个带有静态方法和静态成员的类来计数呢?
此外,您应该使用互锁递增以确保计数正确,并具有某种方式来了解用户何时处于非活动状态,以便可以递减计数。正如评论中指出的那样,这只会为您提供单个进程的计数。如果您在同一台计算机上有多个Web进程或多个服务器,则计数将是错误的-也许这就是返回5的昂贵操作:)