几个月前,我正在面试我目前所在公司的工作,我没有强大的网络开发背景,但他向我提出的一个问题是你如何改进这段代码。 / p>
我完全不记得代码块,但总结一下,它是一个网络点击计数器,并且他使用锁定在hitcounter上。
lock(HitCounter)
{
// Bla...
}
然而经过一些讨论他说,锁是好的,但从未在网络应用程序中使用它!
他的陈述背后的基础是什么?为什么我不能在Web应用程序中使用锁?
答案 0 :(得分:7)
没有特殊原因可以在Web应用程序中使用锁。但是,它们应该被仔细使用,因为它们是一种序列化多线程访问的机制,如果锁定块被争用,这可能导致阻塞。这不仅仅是Web应用程序的一个问题。
值得记住的是现代硬件an uncontended lock takes 20 nanoseconds to flip。考虑到这一点,应该遵循尝试尽可能减少锁定块内部代码的通常做法。如果块中的代码最少,则开销很小,可能会导致争用率低。
要说锁定应该从不使用真的是一个简单的陈述。这实际上取决于您的要求是什么,例如要在请求之间共享的线程安全的内存中缓存可能会导致请求阻塞比从数据库中按需获取更少。
最后,BCL和ASP.Net Framework类型肯定会在内部使用锁,所以无论如何都要间接使用它们。
答案 1 :(得分:6)
应用程序域可能会被回收。
这可能会导致旧的appdomain仍在完成服务某些请求,而新的appdomain也会提供新的请求。
静态变量不会在它们之间共享,因此在这种情况下,锁定静态全局不会授予排他性。
答案 2 :(得分:2)
首先,您永远不想锁定在任何应用程序中实际使用的对象。您想要创建一个锁定对象并锁定:
private readonly object _hitCounterLock = new object();
lock(_hitCounterLock)
{
//blah
}
对于问题的Web部分,当您锁定时,阻止每个尝试访问该对象的线程(对于Web来说可能是数百或数千个用户)。他们都会等到他们前面的每个线程解锁。
答案 3 :(得分:2)
晚了:),但对于未来的读者,还有一点:
如果应用程序在Web场上运行,则在多台计算机上运行的ASP将不共享锁定对象
所以这只能用于 1.不需要支持Web场和2.配置ASP(非默认)不要在回收期间使用并行实例,直到提供旧请求(如上面的Andras所述)
答案 4 :(得分:0)
此代码将为您的应用程序创建一个瓶颈,因为所有传入的请求必须在此之前等待锁定之前等待。
答案 5 :(得分:0)
lock仅用于多线程需要访问同一共享变量的多线程应用程序,因此请求线程专门获取锁定,所有挂起的线程将阻塞并等待锁定被释放。
在Web应用程序中,用户请求是隔离的,因此默认情况下不需要锁定
答案 6 :(得分:0)
有几个理由......
如果您正在尝试锁定数据库读/写操作,则无论如何都会发生竞争条件的高风险,因为数据库不属于执行锁定的进程,因此可以读取来自/写入另一个进程 - 甚至可能是一个假设的未来版本的IIS,它为每个应用程序运行多个进程。
锁通常在客户端应用程序中用于非UI线程,即后台/工作线程。除非您尝试利用多个核心(在这种情况下可以接受与请求相关的对象上的锁定),因此Web应用程序没有多用途进行多线程处理,因为可以假定每个请求都在其上运行自己的线程,服务器无论如何处理整个输出(或至少是顺序chunk)都无法响应。