111,094
社区成员




public ActionResult Index(string uid)
{
var user=GetUser(uid);
if(user==null){
user=CreateUser(uid);//假定耗时1s
}
...
}
static object objLock=new object();
public ActionResult Index(string uid)
{
lock(objLock){
var user=GetUser(uid);
if(user==null){
user=CreateUser(uid);//假定耗时1s
}
...
}
}
public static void Index(string uid)
{
using (UserLocks.LockDown(uid))
{
var user = GetUser(uid);
}
}
class UserLocks : IDisposable
{
static Dictionary<string, object> perUserLocks = new Dictionary<string, object>();
private string userName;
private UserLocks(string userName)
{
this.userName = userName;
}
public static IDisposable LockDown(string userName)
{
object lockObj;
lock (perUserLocks)
{
if (!perUserLocks.TryGetValue(userName, out lockObj))
{
perUserLocks[userName] = lockObj = new object();
}
}
Monitor.Enter(lockObj);
return new UserLocks(userName);
}
void IDisposable.Dispose()
{
object lockObj;
lock (perUserLocks)
{
if (perUserLocks.TryGetValue(userName, out lockObj))
{
Monitor.Exit(lockObj);
}
}
}
}
public User GetLastUser()
{
var key = "Biz_Users_GetLastUser";
User model = null;
if (HttpRuntime.Cache[key] != null)
model = HttpRuntime.Cache[key] as User ;
if (model != null)
return model;
model = GetLastUserFromDb(); //假定耗时100ms
if (model == null)
return null;
HttpRuntime.Cache.Insert(key, model, null, DateTime.Now.AddSeconds(10), Cache.NoSlidingExpiration);
return model;
}
可并发大时,仍然会导致在这100ms里有很多请求进入方法,因为此时缓存并没值,所以全涌入GetFromDb语句了,一些GetFromDb耗时较长的方法上(如获取排名列表等),我又不得不使用Lock了……这种情况,有啥好办法?private static object Lock1234 = new object();
private static object Lock888 = new object();
而对获取其它用户的资料,你完全不应该使用 lock。
这里的逻辑不应该考虑 lock。UserInfo GetUserInfo(string id)
{
var key = "用户_" + id + "_的信息";
var cache = HttpRuntime.Cache;
var res = (UserInfo)cache[key];
if (res == null)
{
res = 查询数据库(id);
cache.Insert(key, res);
}
return res;
}
在 Insert 操作中,你还可以提供更多的输入参数,为缓存单元设置“时间窗口、依赖于某文件改变、依赖于数据库表的变动、依赖于其它缓存单元改变”等等 CacheDependency。
缓存技术的关键不在于会滥用内存,而在于会设置 CacheDependency 从而避免滥用内存来保存脏数据。
回到你的问题本身。当有高并发访问相同的 id 的用户资料时,其实你无法避免一开始就有2、3个任务去同时访问后台数据服务,但是你可以通过缓存技术来避免随后的请求再去访问后台。