繁体   English   中英

C# 锁用 LINQ 查询

[英]C# lock with LINQ query

是否需要如下锁定 LINQ 语句? 如果省略锁,当多个线程同时执行它时,任何异常都会被反击?

lock (syncKey)
{
    return (from keyValue in dictionary
            where keyValue.Key > versionNumber
            select keyValue.Value).ToList();
}

PS:确实存在编写器线程来改变字典。

只要查询没有副作用(例如任何表达式调用代码进行更改),就没有必要锁定 LINQ 语句。

基本上,如果您不修改数据(并且没有其他任何东西在修改您正在使用的数据),那么您就不需要锁。

如果您使用的是 .NET 4.0 并且有一个线程安全的 ConcurrentDictionary。 这是使用并发字典的示例(诚然不在 LINQ 语句中)

更新

如果要修改数据,则需要使用锁。 如果两个或多个线程尝试访问锁定的代码部分,则会有一个小的性能损失,因为一个或多个线程等待锁定被释放。 注意:如果您过度锁定,那么您最终可能会得到更差的性能,如果您从一开始就使用顺序算法构建代码。

如果您只是读取数据,那么您不需要锁,因为没有可变的共享 state 需要保护。

如果您不使用锁,那么您最终可能会出现间歇性错误,其中数据不完全正确,或者当读取器和写入器之间发生冲突时引发异常。 根据我的经验,大多数时候您可能永远不会遇到异常,您只会收到损坏的数据(除非您不一定知道它已损坏)。 这是另一个示例,显示如果您不使用锁或重新设计算法来应对数据如何被破坏

如果您从一开始就考虑在并行系统中开发的限制,您通常会从系统中获得最大的收益。 有时您可以重新编写代码,使其不使用共享数据。 有时您可以将数据拆分成块,并让每个线程/任务在自己的块上工作,然后在最后有一些进程将它们重新缝合在一起。

大多数类型在读取时是线程安全的,但在突变期间不是线程安全的。

如果没有线程正在更改字典,那么您无需执行任何操作 - 只需阅读即可。

但是,如果其中一个线程正在更改它,那么您就会遇到问题并且需要同步。 最简单的方法是lock ,但是即使没有写入器,这也会阻止并发读取器。 如果很有可能您将拥有比作者更多的读者,请考虑使用ReaderWriterLockSlim进行同步 - 这将允许任意数量的读者(没有作者),或者:一个作者。

在 4.0 中,您还可以考虑使用ConcurrentDictionary<,>

如果您的字典是 static 并且您运行查询的方法不是(或其他并发访问场景),并且可以从另一个线程修改字典,那么是的,否则需要锁定 - 不是。

是的,在多线程场景中使用 LINQ 时需要锁定共享资源(编辑:当然,如果您的源集合正在按照 Marc 所说的那样进行修改,如果您只是阅读它,则无需担心)。 如果您使用.Net 4 或 3.5 的并行扩展,您可以考虑用 ConcurrentDictionary 替换您的 Dictionary(或者无论如何使用其他一些自定义实现)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM