我們使用下面的代碼來提高性能。它工作正常,但每隔幾天我們就開始收到大量的例外(如下)。它與音量無關,但是是隨機的。使用緩存鍵鎖定緩存
評論:/ /執行鎖定的代碼,如果有必要,產生的結果,而線程鎖定它,然後緩存結果。
線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:值不能爲空。參數名稱:在System.Web.Caching.CacheInternal.DoGet(布爾isPublic,字符串 鍵,CacheGetOptions getOptions)在PROJECT.LockedCaching.b__8(字符串 K)在PROJECT \ LockedCaching.cs 鍵:64在 線系統。 Collections.Generic.List
1.RemoveAll(Predicate
1匹配)在 PROJECT.LockedCaching.CleanUpOldKeys()在 PROJECT \ LockedCaching.cs:線64在PROJECT \ LockedCaching.cs PROJECTLockedCaching.Request(String鍵,日期時間期滿時, RequestDataOperation數據) :line35 at FeaturesWithFlags1.DataBind()at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp,Object o,Object t,EventArgs e)at System.Web.UI.Control.LoadRecursive()a噸 System.Web.UI.Control.LoadRecursive()處 System.Web.UI.Control.LoadRecursive() System.Web.UI.Control.LoadRecursive()在 System.Web.UI.Control.LoadRecursive ()在 System.Web.UI.Control.LoadRecursive()在 System.Web.UI.Page.ProcessRequestMain(布爾 includeStagesBeforeAsyncPoint,布爾includeStagesAfterAsyncPoint) 在System.Web.UI.Page.HandleError(例外五)在 System.Web.UI.Page.ProcessRequestMain(布爾 includeStagesBeforeAsyncPoint,布爾includeStagesAfterAsyncPoint) 在System.Web.UI.Page.ProcessRequest(布爾 includeStagesBeforeAsyncPoint,布爾includeStagesAfterAsyncPoint)System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() System.Web.UI.Page.ProcessRequest(HttpContext上下文)在System.Web.UI.Page.ProcessRequest()在System.Web.HttpApplication.ExecuteStep(IExecutionStep一步, 布爾& completedSynchronously)使用它的
Web控件 - 這一網絡控制請求,從web服務位置的列表。我們使用這個lockedcache要求幾乎無處不在,我們稱之爲Web服務:
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();
}
謝謝您的意見。 ConcurrentDictionary是要走的路。我們收到錯誤的原因是因爲linq代碼「lock(_keys.First(k => k == key))」返回一個異常而不是null。使用並行字典將會更安全,並且不會導致任何鎖定問題。
修改代碼:
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_的第一個元素嗎?這不是'lock'的工作方式。 –
你的代碼是非線程安全的。您應該使用ReaderWriterLock,或者只使用一個'ConcurrentDictionary'。 – SLaks
如果'_keys'應該是專門用於鎖定目的的同步列表,那麼在訪問集合時'_keys'本身必須被鎖定。雖然我不確定你的代碼的目的是什麼。 –