首先,先做好事.这是支持团队提供的一些异常信息.我知道它发生的行和代码.它发生在对从缓存中获取的字典的FirstOrDefault调用中.
1) Exception information ********************************************* Exception Type: system.invalidOperationException Message: Collection was modified; enumeration operation may not execute. Data: System.Collections.ListDictionaryInternal
现在我想模拟问题,我可以在一个简单的ASP.net应用程序中完成.
我的页面有2个按钮 – Button_Process和Button_Add
背后的代码如下:
public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender,EventArgs e) { if (!IsPostBack) { var data = Cache["key"]; if (data == null) { var dict = new Dictionary<int,string>(); for (int i = 0; i < 10; i++) { dict.Add(i,"i"); } Cache["key"] = dict; } } } protected void ButtonProcess_Click(object sender,EventArgs e) { var data = Cache["key"] as Dictionary<int,string>; if (data != null) { foreach (var d in data.Values) //In actual code there is FirstOrDefault here { Thread.Sleep(1000); if (d.Contains("5")) { //some operation } } } } protected void Button2_Click(object sender,string>; if (data != null) { data.Add(new Random().Next(),"101"); Cache["key"] = data; } } }
现在假设有2个请求:
请求1 – 有人点击了button_Process,并且正在对缓存对象进行一些操作
请求2 – 有人点击button_Add并且第一个人获得异常 – 集合修改了等等
我理解这个问题 – 它正在发生,因为我们正在访问相同的内存.我脑子里有两个解决方案:
1.我使用for循环而不是每个循环(在实际代码中替换FirstOrDefault) – 我不知道在进行更改后此操作的效率如何. – 我从来没有从缓存中删除任何项目,所以我在想这个解决方案
2.我对这些行上的缓存对象或其他东西进行了一些锁定 – 但我确切地知道在哪里以及如何锁定这个对象.
解决方法
发生这种情况是因为您直接使用对象,位于缓存中.良好的做法,避免那些异常和其他奇怪的行为(当你不小心修改缓存对象)正在使用缓存数据的副本.有几种方法可以实现它,比如做克隆或某种深层复制.我更喜欢将对象保存在高速缓存中序列化(您喜欢的任何类型 – json / xml / binary或w / e else),因为(de)序列化会对您的对象进行深层复制.以下小代码片段将澄清一些事情:
public static class CacheManager { private static readonly Cache MyCache = httpruntime.cache; public static void Put<T>(T data,string key) { MyCache.Insert(key,Serialize(data)); } public static T Get<T>(string key) { var data = MyCache.Get(key) as string; if (data != null) return Deserialize<T>(data); return default(T); } private static string Serialize(object data) { //this is Newtonsoft.Json serializer,but you can use the one you like return JsonConvert.SerializeObject(data); } private static T Deserialize<T>(string data) { return JsonConvert.DeserializeObject<T>(data); } }
用法:
var myObj = new Dictionary<int,int>(); CacheManager.Put(myObj,"myObj"); //... var anotherObj = CacheManager.Get<Dictionary<int,int>>("myObj");
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。