有什么能比Concurrent集合更好地解决这个多线程场景

时间:2015-02-16 23:27:50

标签: c# multithreading dictionary concurrency concurrentdictionary

我有一个持久的B +树,多个线程正在读取树的不同块并对读取数据执行一些操作。 有趣的部分:每个线程产生一组结果,作为最终用户,我想在一个地方看到所有结果。 我做什么:一个ConcurentDictionary,所有线程都写入它。

这一切都很顺利。但是应用程序是时间关键的,一秒钟意味着完全不满意。与Dictionary相比,ConcurentDictionary由于线程安全开销本质上很慢。

我可以使用Dictionary,然后每个线程都会将结果写入不同的词典。但是我会遇到合并不同词典的问题。

我的问题:

  1. 并发收集是否适合我的方案?
  2. 如果不是(1),那么我将如何合并最佳不同的词典。鉴于此,(a)逐个复制项目和(b) LINQ是已知的解决方案,并不像预期的那样最佳:)
  3. 如果不是(2);-)你会建议什么?
  4. 快速信息:

    • #Thread = processorCount。应用程序可以在标准笔记本电脑(即4个线程)或高端服务器(即< 32个线程)上运行
    • 项目计数。该树通常拥有超过1.0E + 12项。

2 个答案:

答案 0 :(得分:2)

从你的时间看,结果字典的锁定/构建似乎每个线程需要3700ms,实际处理逻辑只需要300ms。

我建议你作为一个实验让每个线程创建自己的本地结果字典。然后你可以看到构建字典所花费的时间与跨线程锁定的效果相比有多少。

如果构建本地词典增加超过300毫秒,那么将无法满足您的时间限制。因为没有任何锁定或任何尝试合并结果,它已经花了太长时间。

<强>更新

您似乎可以随时支付合并价格,锁定会导致线程闲置很长一段时间,或者在后处理合并中支付价格。但核心问题是锁定意味着你没有充分利用可用的CPU。

从核心获得最大性能的唯一真正解决方案是使用非线程安全的非阻塞字典实现。我找不到.NET实现,但确实找到了一份研究报告,详细说明了一种可能表明它是可能的算法。

正确实现这样的算法并非易事,但会很有趣!

Scalable and Lock-Free Concurrent Dictionaries

答案 1 :(得分:0)

您是否考虑过异步持久性?

你的情景允许吗?

您可以绕过分离的线程池中的队列(创建线程池可以避免为每个请求创建(子)线程的开销),并且您可以在不影响响应时间的情况下处理合并逻辑。