5
不推荐使用lock。
前台ajax访问时,点击按钮提交后,通过ajax的beforesend,显示一个等待的图标。当提交完成后,ajax的complete取消这个图标,来防止用户重复点击提交按钮。
前台ajax访问时,点击按钮提交后,通过ajax的beforesend,显示一个等待的图标。当提交完成后,ajax的complete取消这个图标,来防止用户重复点击提交按钮。
150
lock 针对的就是单个的对象,所以你懂的,要想针对单个 uid 进行加锁,那么你首先设计能够保存针对单个uid所创建的数据结构就行了。
例如 Dictionary<stirng, object> LockFlags。
或你先使用 GetUserLockFlag(uid) 获取加锁对象,然后再使用 lock 来加锁。此时这个 GetUserLockFlag 由于是纯粹内存操作,自然不会用1s这么长时间。
回到你的问题本身,实际上“高并发情况下CreateUser重复执行”这并不是应该使用 lock 的理由!要想避免重复查询数据库,那么就应该把查询结果放到 Cache 实例中,例如可能写
例如 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就是锁。
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); } } } }