c# - 极端线程安全集合

标签 c# multithreading linq concurrency concurrentdictionary

我在 .Net 4.5 中有一个 ConcurrentBag,我从数据库中存储了大约 4,000 行。我正在存储 DTO。

我的整个应用程序都依赖于此。我有返回整个列表的函数,也有返回单个项目的函数。我在代码中的很多地方都在对集合等进行 LINQ 查询。

我将其全部推向生产环境,在获得可观流量的网​​站上,并立即 100% cpu。我用了iis诊断工具,果然有50+线程死锁,等待ConcurrentBag。

文档说这个集合是线程安全的,但要么这不是真的,要么这个集合的性能不好从而间接地使其不是线程安全的。

不幸的是,这个集合不是只读的。如果按 ID 查找的函数之一返回 null,它将访问 Web 服务并添加它。

我也将它转换为 ConcurrentDictionary,但遇到了同样的问题。在 .Values 属性上锁定 Days。

在最极端的情况下,最快和最线程安全的解决方案是什么?

private ConcurrentBag<Students> _students;
public static ConcurrentBag<DestinyHash> GetStudents()
{
   if (_students == null) { _students = new ConcurrentBag<Students>(); }

   return _students;
}

public static Student GetStudentByID(int id) 
{
   if (GetStudents().Any(x => x.id == id)) { return ... }

   _students.Add(getStudentFromDb(id));
   return...
}

示例用法 - 遍及整个应用程序。

Helper.GetStudents().FirstOrDefault(x => x.name == "foo" && x.status == "bar");
Helper.GetStudentByID(50);

最佳答案

简单的答案是您使用了错误的容器。

ConcurrentBag不是通用的。它更像是一个可重用对象池,您可以(通常作为最后一步)将其缩减为单个非并发值。它可用于解决的一个此类问题是同时对列表求和。

如果您主要使用 ConcurrentBag偏离添加/删除,并且您经常枚举集合,那么您使用它是错误的。

如果您发布更多代码,您将获得更有针对性的帮助。并发性是理解问题对于提供高性能解决方案非常重要的领域之一。

编辑:

ConcurrentDictionary将为您正在做的事情工作。诀窍是你不想使用 ConcurrentDictionary.Values -- 这将锁定字典并复制其内容。如果你只是使用它的 IEnumerable<T>接口(interface),你会没事的。例如:

private ConcurrentDictionary<int,Student> _students;

public static IEnumerable<Student> GetStudents()
{
   return _students.Select(x => x.Value);
}

public static Student GetStudentByID(int id) 
{
   Student s;
   if(_students.TryGetValue(id, out s)) return s;

   s = getStudentFromDb(id);
   _students[id] = s;

   return s;
}

关于c# - 极端线程安全集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32029956/

相关文章:

c# - 通过 Response 发送内存中生成的 .PDF 文件

c# - XAML 检测 ListView 项目是否获得焦点

Python 2.6 使用 Apache 线程化 KeyError

java - 跨线程保留 Java 堆栈跟踪

c# - 我想在 linq 中添加 2 个月后的月份和年份

c# - C# 不同数据库的MySQL数据同步

c# - 异常 System.Reflection.TargetInvocationException - Backgroundworker

java - 当 swingWorker 线程完成时,我是否需要收集它们?

c# - 使用 LINQ 组合给定数据表列中的项目

c# - 如何使用 LINQ 从 IEnumerable 中选择随机项