Fee*_*ech 5 c# rest multithreading block pulse
我们有一个类似于以下的REST API方法:
List<item> GetItems(int AccountID)
{
var x = getFromCache(AccountID);
if(x==null)
{
x = getFromDatabase(AccountID);
addToCache(AccountID, x);
}
return x;
}
Run Code Online (Sandbox Code Playgroud)
这是一个相当昂贵的方法,有一些复杂的数据库调用,我们有一个常见的情况,数百名具有相同AccountId的用户几乎会同时进行调用(他们都通过广播通知).
在该方法中,我们将结果集缓存10秒,因为对于在该窗口内发出请求的每个人来说,近期结果都很好.但是,由于它们都同时进行调用(同样,对于特定的AccountID),缓存永远不会预先填充,因此每个人最终都会进行数据库调用.
所以我的问题是,在该方法中,如何暂停特定accountId的所有传入请求并使它们等待第一个结果集完成,以便其余的调用可以使用缓存的结果集?
我已经阅读了一些关于Monitor.Pulse和Monitor.Lock的内容,但是每个accountId锁的实现让我感到安慰.任何帮助将非常感激.
对于具有相同 AccountId 的请求,您必须锁定同一对象,但对每个单独的 AccountId 使用不同的对象。以下是如何使用 Dictionary 来跟踪各个 AccountId 的锁定对象的示例。
Dictionary<int, Object> Locks = new Dictionary<int, object>();
List<item> GetItems(int AccountID)
{
//Get different lock object for each AccountId
Object LockForAccountId = GetLockObject(AccountID);
//block subsequent threads until first thread fills the cache
lock (LockForAccountId)
{
var x = getFromCache(AccountID);
if (x == null)
{
x = getFromDatabase(AccountID);
addToCache(AccountID, x);
}
return x;
}
}
private Object GetLockObject(int AccountID)
{
Object LockForAccountId;
//we must use global lock while accessing dictionary with locks to prevent multiple different lock objects to be created for the same AccountId
lock (Locks)
{
if (!Locks.TryGetValue(AccountID, out LockForAccountId))
{
LockForAccountId = new Object();
Locks[AccountID] = LockForAccountId;
}
}
return LockForAccountId;
}
Run Code Online (Sandbox Code Playgroud)