如果在修改字典时没有锁定字典会发生什么?关于asp.net缓存

win*_*goo 0 asp.net caching dictionary locking thread-safety

对不起,我有很多关于锁/缓存的问题.= _ = ..

- > 1.关于缓存,我知道asp.net中的缓存是线程安全的,我通常使用的简单代码是

    IList<User> user= HttpRuntime.Cache["myCacheItem"] as IList<User>;
    if (user == null)
    { 
       //should i have a lock here?
       //lock(some_static_var){...}
       HttpRuntime.Cache["myCacheItem"] = GetDateFromDateBase();
    }

    return user;
Run Code Online (Sandbox Code Playgroud)

应该在代码中使用锁?

- > - > 1.1如果我使用,也许我应该申报许多锁定项目?我在社区服务器上看到了一些实现,它使用静态字典来存储锁定项,这是个好主意吗?因为我担心字典中的锁定项可能太多而且它可能会减慢系统速度.

- > - > 1.2如果我不使用,会发生什么?只是可能有两个或更多线程访问GetDateFromDateBase()?如果只是这个,我想也许我可以放弃锁定.

- > 2.i有一个存储在缓存中的通用字典,我必须修改(添加/更新/删除)它.我只是用它来获取像dic.trygetvalue(key)这样的值,不要循环它.

- > - > 2.1如果我可以保证修改只发生在一个线程中,场景就像
a.aspx - >从缓存中读取字典,并在页面上显示,public for user
b.ashx - >将修改调用它时的字典.(在5分钟内循环),私人使用

我应该在a/b中使用锁吗?锁定读者和作家?
- > - > - > 2.11如果我不使用任何锁,会发生什么?当读者和作者同时访问时,它会抛出异常吗?
- > - > - > 2.12如果我只是将作者锁定在b.ashx中,会发生什么?a.aspx中的读者会被阻止吗?什么是处理这种情况的最佳做法?

- > - > 2.2如果读写器都出现在多线程访问中.他们都是公共页面.
a.aspx - >只是从缓存中读取
b.aspx - >修改字典

该怎么办?锁定所有?

- > - > 2.3如果我实现了一个新的字典添加功能:
它只是将当前字典复制到一个新字典,然后添加新项目或修改,最后返回新的字典,它会解决并发问题吗?

哈希表会解决这些问题吗?

如何确定需要锁定的项目?我觉得我在这些事情上错了= _ =.

- > 3.最后一个问题 ..我有两个web应用程序
- >显示web
b - > mamage一些设置
它们都有自己的缓存,我可以并发两个缓存吗?
将[2.1]中的操作正确或其他操作吗?(我测试memcached但它比在Web应用程序中太慢,所以我只使用两个)

谢谢你阅读全部-_-
祝你知道我说的话:)

更新 ================================================= =====
感谢Aaron的回答.在看完他的答案之后,我试着回答自己:)
1.关于缓存,如果数据不会修改,它可以先在Application_Start(global.asax)中读入缓存.
1.1如果锁定,我应该在读取数据时添加锁定启动,而不仅仅是写入.锁定项目应该是静态的,但我也觉得uncerrain约1.1.
1.2是的,如果你可以假设代码只是从数据库读取日期然后插入缓存而不会修改(对吗?-_-).这个结果可能会从数据库中多次读取.我认为这不是一个大问题.

2.通用字典写入不是线程安全的,所以修改时应该锁定.要解决这个问题,我可以使用不可变的字典.
但如果我ConcurrentDictionary在.net4.0中使用(读/写时的线程安全)或者我自己实现一个新的字典(使用读写器锁),它会解决吗?我需要在修改时再次锁定吗?代码就像

ConcurrentDictionary user= HttpRuntime.Cache["myCacheItem"] as ConcurrentDictionary;
if (user == null)
{ 
   //is it safe when the user is ConcurrentDictionary?
   HttpRuntime.Cache["myCacheItem"] = GetDateFromDateBase();
}
else
{
    //is it safe when the user is ConcurrentDictionary?
    user["1"] = a_new_user;
}
Run Code Online (Sandbox Code Playgroud)


3.问题是,我有一个像stroe这样的小应用程序,它有两个web应用程序,一个是商店展示站点(A),另一个是管理站点(B),所以我需要同意两个web缓存,就像我修改B中的产品价格一样,我如何通知网站A更改/删除缓存?(我知道A中的缓存可以设置短路,但不是很快,所以我想知道那里有内在在asp.net中支持或者像问题2.1一样?有一个aspx/ashx页面可以调用吗?)

Aar*_*ght 6

线程安全意味着您不必担心多个线程同时读取和写入相同的单个缓存项.您不需要任何类型的锁来进行简单的读写操作.

但是,如果您尝试执行应该是原子操作的操作 - 例如,检查项目是否存在并添加它(如果它不存在),则需要同步或序列化访问.由于锁必须是全球性的,它通常是最好声明一个static readonly object在你global.asax和执行原子操作之前锁定这一点.请注意,您应该在读取之前锁定并且仅在写入后释放锁定,因此上述示例中的假设锁定实际上发生得太晚.

这就是许多Web应用程序不会延迟加载缓存的原因; 相反,它们在Application_Start方法中执行加载.至少,将一个空字典放入缓存可以省去检查的麻烦,null这样你就不必同步了,因为你只能访问缓存项一次(但继续阅读).

该问题的另一个方面是,即使缓存本身是线程安全的,它也不会使您添加的任何项目都是线程安全的.这意味着如果你在那里存储一个字典,任何检索缓存项的线程都可以保证获得一个完全初始化的字典,但如果有多个请求试图访问,你仍然可以创建竞争条件和其他线程安全问题字典同时至少有一个修改它.

.NET中的字典可以支持多个并发读取器,但不支持编写器,因此如果您在ASP.NET缓存中存储了一个字典并且有多个线程/请求读写,那么您肯定会遇到问题.如果您可以保证只有一个线程可以写入字典,那么您可以将Dictionary用作不可变类型 - 即复制字典,修改副本,并用副本替换缓存中的原始字符.如果字典不经常修改,那么这确实可以省去同步访问的麻烦,因为没有请求会尝试从正在修改的同一字典中读取.另一方面,如果字典非常大和/或经常被修改,那么您可能会遇到制作所有这些副本的性能问题 - 唯一可以确定的是配置文件,配置文件,配置文件!

如果您发现性能限制不允许使用该方法,则唯一的其他选择是同步访问.如果您知道一次只有一个线程会修改字典,那么读写器锁定(即ReaderWriterLockSlim)应该适合您.如果你不能保证这一点,那么你需要一个Monitor(或者只是lock(...)围绕每个操作序列的简单子句).

这应该回答问题1-2; 对不起,但我不太明白你在#3中提出的问题.ASP.NET应用程序都在他们自己的AppDomains中实例化,所以没有任何并发​​问题可以说,因为没有任何共享(除非你实际上使用的是IPC的某种方法,在这种情况下,一切都是公平的游戏).

我是否正确理解了您的问题?这有帮助吗?