나는 사용자가 EF를 통해 로그인 할 때 WebUser
객체를로드하는 웹 포털에서 일하고 있어요 문제점작업은 동 기적으로
실행 컨트롤러 액션의 시작. WebUser
은 사소한 개체 그래프가 있으며 EF를 통해로드하는 데 2-3 초가 걸릴 수 있습니다 (로드 시간을 최적화하는 것이 별도의 문제 임).
인식 성능을 향상시키기 위해 사용자가 시스템에 별도의 스레드에 로그온하자마자 WebUser
을로드하려고합니다. 그러나 현재의 시도는 내가 이해할 수없는 이유로 동 기적으로 실행됩니다.
강령
static private ConcurrentDictionary<string, WebUser> userCache =
new ConcurrentDictionary<string, WebUser>();
static public void CacheProfile(string userName)
{
if (!userCache.ContainsKey(userName))
{
logger.Debug("In CacheProfile() and there is no profile in cache");
Task bg = GetProfileAsync(userName);
logger.Debug("Done CacheProfile()");
}
}
static public async Task<WebUser> GetProfileAsync(string userName)
{
logger.Debug("GetProfileAsync for " + userName);
await currentlyLoading.NotInSet(userName); // See NOTE 1 below
if (userCache.ContainsKey(userName))
{
logger.Debug("GetProfileAsync from memory cache for " + userName);
return userCache[userName];
}
else
{
currentlyLoading.Add(userName);
logger.Debug("GetProfileAsync from DB for " + userName);
using (MembershipContext ctx = new MembershipContext())
{
ctx.Configuration.LazyLoadingEnabled = false;
ctx.Configuration.ProxyCreationEnabled = false;
ctx.Configuration.AutoDetectChangesEnabled = false;
var wu = GetProfileForUpdate_ExpensiveMethod(ctx, userName);
userCache[userName] = wu;
currentlyLoading.Remove(userName);
return wu;
}
}
}
주 1 : currentlyLoading
은 ConcurrentWaitUntil<T>
의 정적 인스턴스입니다. 첫 번째 요청이 여전히 데이터베이스에서로드되는 경우 의도 된 사용자의 프로필에 대한 두 번째 요청이 차단되도록하는 것이 그 의도입니다. 아마도 이것을 성취하는 더 좋은 방법이 있을까요? 코드 :
public class ConcurrentWaitUntil<T>
{
private HashSet<T> set = new HashSet<T>();
private Dictionary<T, TaskCompletionSource<bool>> completions = new Dictionary<T, TaskCompletionSource<bool>>();
private object locker = new object();
public async Task NotInSet(T item)
{
TaskCompletionSource<bool> completion;
lock (locker)
{
if (!set.Contains(item)) return;
completion = new TaskCompletionSource<bool>();
completions.Add(item, completion);
}
await completion.Task;
}
public void Add(T item)
{
lock (locker)
{
set.Add(item);
}
}
public void Remove(T item)
{
lock (locker)
{
set.Remove(item);
TaskCompletionSource<bool> completion;
bool found = completions.TryGetValue(item, out completion);
if (found)
{
completions.Remove(item);
completion.SetResult(true); // This will allow NotInSet() to complete
}
}
}
}
이
왜 CacheProfile()
이 GetProfileAsync()
때까지 기다려야 할 것 같다 않는 질문이
참고 : ConcurrentDictionary
은 확장 성이 뛰어나며 ASP.Net의 캐시를 사용해야한다는 것을 알고 있습니다.
'GetProfileAsync()'의 완전한 코드를 추가했습니다. 첫 번째 메소드 호출은'await'입니다. 현재 라인 목록과 사용자 이름을 프로파일 목록에 추가하는 선 사이에 잠재적 경쟁 조건이 있음을 알고 있습니다. 두 번째 요청은 실제 클릭에 의해 트리거되므로 실제로이 경우에는 발생하지 않습니다. 이제는 결과가 아닌 작업을 캐싱하기위한 패턴을 찾고 있습니다. –
사이드 노트에서 이전에는 결코 ' _은 유효한 매개 변수 이름입니다. –
결과가 아닌 작업을 캐싱 할 때 메모리 내 캐시를 업데이트하는 방법은 무엇입니까? 메모리 내 표시를 업데이트하고 변경 내용을 DB. 이것은 http://entityframework.codeplex.com/workitem/864 –