성능 향상을 위해 아래 코드를 사용합니다. 그것은 잘 작동하지만 몇 일마다 우리는 (아래) 예외 톤을 받기 시작합니다. 볼륨과 관련이 없지만 무작위입니다.캐시 키를 사용하는 잠긴 캐싱
설명 : 필요한 경우 스레드를 잠근 다음 결과를 캐싱하는 동안 잠긴 코드를 수행하여 결과를 생성합니다.
라인 (45)은 : 로크 (_keys.First (K => K == 키))
어떤 아이디어?
코드 :
public class LockedCaching
{
private static List<string> _keys = new List<string>();
public class Result
{
public object Value { get; set; }
public bool ExecutedDataOperation { get; set; }
}
/// <summary>
/// Performs the locked code to produce the result if necessary while thread locking it and then caching the result.
/// </summary>
/// <param name="key"></param>
/// <param name="expiration"></param>
/// <param name="data"></param>
/// <returns></returns>
public static Result Request(string key, DateTime expiration, RequestDataOperation data)
{
if (key == null)
{
return new Result { Value = data(), ExecutedDataOperation = true };
}
//Does the key have an instance for locking yet (in our _keys list)?
bool addedKey = false;
bool executedDataOperation = false;
if (!_keys.Exists(s => s == key))
{
_keys.Add(key);
addedKey = true;
}
object ret = HttpContext.Current.Cache[key];
if (ret == null)
{
lock (_keys.First(k => k == key))
{
ret = HttpContext.Current.Cache[key];
if (ret == null)
{
ret = data();
executedDataOperation = true;
if(ret != null)
HttpContext.Current.Cache.Insert(key, ret, null, expiration, new TimeSpan(0));
}
}
}
if (addedKey)
CleanUpOldKeys();
return new Result { Value = ret, ExecutedDataOperation = executedDataOperation };
}
private static void CleanUpOldKeys()
{
_keys.RemoveAll(k => HttpContext.Current.Cache[k] == null);
}
}
예외 :
예외 : System.Web.HttpUnhandledException (0X80004005) 형식 'System.Web.HttpUnhandledException'의 는 던져졌다 예외입니다. ---> System.ArgumentNullException : 값은 null 일 수 없습니다. 매개 변수 이름 : 프로젝트 \의 LockedCaching.cs에서 PROJECT.LockedCaching.b__8에서 System.Web.Caching.CacheInternal.DoGet (부울 isPublic, 문자열 키 CacheGetOptions의 getOptions() 문자열 K)에서 키 : 라인 64 에서 시스템. 라인 64 PROJECT \ LockedCaching.cs에서 PROJECTLockedCaching.Request (문자열 키, 날짜 시간 만료, RequestDataOperation 데이터)에서 : 프로젝트 \의 LockedCaching.cs에서 PROJECT.LockedCaching.CleanUpOldKeys()에서 Collections.Generic.List
1.RemoveAll(Predicate
1 경기) : 줄 58에서 FeaturesWithFlags1.DataBind() 에서 System.Web.UI.Control.LoadRecursive()에서 System.Web.Util.CalliHelper.EventArgFunctionCaller (IntPtr fp, Object , Object t, EventArgs e) t 에서 System.Web.UI.Control.LoadRecursive() 에서 System.Web.UI.Control.LoadRecursive() 에서 System.Web.UI.Control.LoadRecursive() System.Web.UI.Control.LoadRecursive()에 System.Web.UI.Page.HandleError에서 System.Web.UI.Page.ProcessRequestMain (부울 includeStagesBeforeAsyncPoint 부울 includeStagesAfterAsyncPoint) 에서 System.Web.UI.Control.LoadRecursive() (예외 E)에서 System.Web.UI.Page.ProcessRequestMain System.Web.UI.Page.ProcessRequest에서 (부울 includeStagesBeforeAsyncPoint 부울 includeStagesAfterAsyncPoint) (부울 includeStagesBeforeAsyncPoint 부울 includeStagesAfterAsyncPoint),745 System.Web.UI.Page.ProcessRequest()의의 System.Web.UI.Page.ProcessRequest (HttpContext context) System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() 이 웹 제어를 요청한다 웹 서비스에서 위치 목록 - System.Web.HttpApplication.ExecuteStep 때 (IExecutionStep 단계, 부울 & completedSynchronously)이 사용되는
웹 컨트롤에서. 우리는 우리가 웹 서비스 :
public override void DataBind()
{
try
{
string cacheKey = "GetSites|";
mt_site_config[] sites = (mt_site_config[])LockedCaching.Request(cacheKey, DateTime.UtcNow.AddMinutes(10),
() =>
{
WebServiceClient service = new WebServiceClient();
sites = service.GetSites();
service.Close();
return sites;
}).Value;
ddlLocation.Items.Clear();
ddlLocation.Items.Add(new ListItem("Please Select"));
ddlLocation.Items.Add(new ListItem("Administration"));
ddlLocation.Items.AddRange
(
sites.Select
(
s => new ListItem(s.site_name + " " + s.site_location, s.th_code.ToString())
).ToArray()
);
}
catch (Exception ex) {
Logger.Error("ContactUs Control Exception: Exp" + Environment.NewLine + ex.Message);
}
base.DataBind();
}
는 귀하의 의견 주셔서 감사 전화를 거의 모든 곳이 lockedcache 요청을 사용합니다. ConcurrentDictionary가 방법이었습니다. 우리가 오류를받은 이유는 linq 코드 "lock (_keys.First (k => k == key))"이 null이 아닌 예외를 반환했기 때문입니다.concurrentdictionary를 사용하면 훨씬 안전 해지고 잘하면 잠금 문제가 발생하지 않습니다.수정 된 코드 :
public class LockedCaching
{
public class Result
{
public object Value { get; set; }
public bool ExecutedDataOperation { get; set; }
}
public static Result Request(string key, DateTime expiration, RequestDataOperation data)
{
if (key == null)
{
return new Result { Value = data(), ExecutedDataOperation = true };
}
object results = HttpContext.Current.Cache[key];
bool executedDataOperation = false;
if (results == null)
{
object miniLock = _miniLocks.GetOrAdd(key, k => new object());
lock (miniLock)
{
results = HttpContext.Current.Cache[key];
if (results == null)
{
results = data();
executedDataOperation = true;
if (results != null)
HttpContext.Current.Cache.Insert(key, results, null, expiration, new TimeSpan(0));
object temp;
object tempResults;
if (_miniLocks.TryGetValue(key, out temp) && (temp == miniLock))
_miniLocks.TryRemove(key, out tempResults);
}
}
}
return new Result { Value = results, ExecutedDataOperation = executedDataOperation };
}
private static readonly ConcurrentDictionary<string, object> _miniLocks =
new ConcurrentDictionary<string, object>();
}
왜 식을 잠그려고합니까? 코드가 실제로 첫 번째 요소 인 _locks_이라고 생각합니까? 그건'자물쇠'가 작동하는 방식이 아닙니다. –
코드가 스레드로부터 안전하지 않습니다. ReaderWriterLock을 사용하거나 하나의 'ConcurrentDictionary'만 사용해야합니다. – SLaks
'_keys'가 잠금 목적으로 특별히 사용 된 syncroots의리스트라고 가정하면,'_keys'는 콜렉션에 접근하는 동안 그 자체가 잠길 필요가 있습니다. 비록 의도가 당신의 코드를 어떻게 바라보고 있는지 잘 모르겠지만. –