Code Bye

讨教下关于锁的用法

5

不推荐使用lock。
前台ajax访问时,点击按钮提交后,通过ajax的beforesend,显示一个等待的图标。当提交完成后,ajax的complete取消这个图标,来防止用户重复点击提交按钮。

150

lock 针对的就是单个的对象,所以你懂的,要想针对单个 uid 进行加锁,那么你首先设计能够保存针对单个uid所创建的数据结构就行了。
例如  Dictionary<stirng, object> LockFlags。
或你先使用 GetUserLockFlag(uid) 获取加锁对象,然后再使用 lock 来加锁。此时这个 GetUserLockFlag 由于是纯粹内存操作,自然不会用1s这么长时间。
回到你的问题本身,实际上“高并发情况下CreateUser重复执行”这并不是应该使用 lock 的理由!要想避免重复查询数据库,那么就应该把查询结果放到 Cache 实例中,例如可能写
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个任务去同时访问后台数据服务,但是你可以通过缓存技术来避免随后的请求再去访问后台。

20

CreateUser假如是数据库出现重复等问题,应该在数据库层面解决。原因是:
1、”高并发“的最直接的解决办法,就是增加服务器。
2、任何在本地加锁,解决CreateUser重复的方法,对多个服务器没有效果。
假如,你只关心‘本地’的重复执行问题。那么,你可以减低加锁的范围,可以不同的uid对应一个锁。
数据结构上可以用Dictionary<string, object>,key就是uid,object就是锁。

5

例如说,假如你的软件总是在一启动时就集中去取固定某两位用户的 UserInfo,你可以单独设置两个 lockflag,例如
private static object Lock1234 = new object();
private static object Lock888 = new object();

而对获取其它用户的资料,你完全不应该使用 lock。
这里的逻辑不应该考虑 lock。

20

假如是优化是避免本地重复操作,那么:
        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);
            }
        }
    }
}

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明讨教下关于锁的用法