我正在开发一个应用程序,它可以扫描数千个结构的副本; ~1 GB RAM。速度很重要。
ParallelScan(_from, _to); //In a new thread
我手动调整线程数:
if (myStructs.Count == 0) { threads = 0; }
else if (myStructs.Count < 1 * Number.Thousand) { threads = 1; }
else if (myStructs.Count < 3 * Number.Thousand) { threads = 2; }
else if (myStructs.Count < 5 * Number.Thousand) { threads = 4; }
else if (myStructs.Count < 10 * Number.Thousand) { threads = 8; }
else if (myStructs.Count < 20 * Number.Thousand) { threads = 12; }
else if (myStructs.Count < 30 * Number.Thousand) { threads = 20; }
else if (myStructs.Count < 50 * Number.Thousand) { threads = 30; }
else threads = 40;
我刚刚从头开始编写它,我需要为另一个CPU等修改它。我想我可以编写一个更聪明的代码,如果CPU现在可用,它会动态启动一个新线程:
有没有人认为“我做过类似的事情”或“我有更好的主意”?
更新:解决方案
Parallel.For(0, myStructs.Count - 1, (x) =>
{
ParallelScan(x, x); // Will be ParallelScan(x);
});
我确实修剪了大量的代码。谢谢大家!
更新2:结果
扫描10K模板的时间
答案 0 :(得分:5)
标准答案:使用任务(TPL),而不是线程。任务需要Fx4。
您的ParallelScan可以使用Parallel.Foreach( ... )
或PLINQ(.AsParallel()
)。
TPL框架包括一个调度程序,ForEach()
使用分区程序来适应CPU核心和负载。您的问题最有可能通过标准组件解决,但您可以编写自定义调度程序和分区程序。
答案 1 :(得分:3)
实际上,如果CPU只有两个核心(即使每个核心都支持超线程),你将无法从跨越50个线程中获益。如果由于每隔一段时间就会发生的上下文切换,实际上会运行较慢。
这意味着您应该选择Task Parallel Library (.NET 4),这样可以有效地使用所有可用内核。
除此之外,无论摩尔定律如何,改善搜索算法的渐近持续时间对于大量数据可能更有价值。
<强> [编辑] 强>
如果您不能/不愿意使用.NET 4 TPL,您可以首先获取系统中当前逻辑处理器数的信息(使用Environment.ProcessorCount
或检查{ {3}}详细信息)。根据该数字,您可以对数据进行分区并跨越固定数量的线程。这比检查CPU利用率要简单得多,并且应该防止创建不必要的线程,这些线程无论如何都是饥饿的。
答案 2 :(得分:2)
好的,抱歉继续,但首先要编译我的评论:
我对你的表演固定感到困惑,部分原因是因为你说你正在查看50,000个结构(一个非常快速和简单的操作),部分是因为你正在使用结构。没有装箱是值类型,如果你在线程周围传递它们,你就是复制数据而不是引用,即使用更多内存。我的观点是,这是大量的数据/内存,除非结构很小,在这种情况下,你可以对它们做什么样的处理,只需要考虑并行40多个线程?
如果性能真的非常重要并且您的目标,并且您不是简单地尝试将其作为一项精彩的工程练习,那么请分享您正在进行的处理类型的信息。