编程语言
首页 > 编程语言> > c# – 极端线程安全集合

c# – 极端线程安全集合

作者:互联网

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

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

我将它全部投入生产,在现场获得可观的流量,并立即100%cpu.我使用了iis诊断工具,果然,死锁中有50个线程,等待ConcurrentBag.

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

遗憾的是,这个集合不是只读的.如果通过ID查找的其中一个函数返回null,它将访问Web服务并添加它.

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

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

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>界面,你会没事的.例如:

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,multithreading,linq,concurrency,concurrentdictionary
来源: https://codeday.me/bug/20190528/1169427.html