比方说,我有一个包含 500 个对象的列表。对于每个对象,我正在调用一个函数来计算它的成本。因此,500 个调用中的每一个都独立于其他调用。整个过程大约需要 30 秒。难道不能同时运行所有 500 个任务,因为它们不相互依赖吗?我对多线程一无所知,因此我不知道它是否可以成为解决方案。
6 回答
您可以使用Parallel.ForEach 方法轻松地并行化工作:
Parallel.ForEach(items, item =>
{
item.CalculateCost();
});
运行单线程进程将仅使用您机器的一个核心(这确实允许其他核心运行操作系统和其他应用程序进程)。
您的进程听起来是多线程处理的一个很好的竞争者,但是您不需要每个进程都有一个新线程 - 这会在创建线程时产生开销,而且您将没有足够的内核来单独运行它们,因此他们将争夺 CPU 资源。
在 .Net4.0 中使用Parallel.For
会巧妙地使用尽可能多的线程。
使用任务并行库为每个对象启动一个单独的任务。在任务中,您将调用该函数来计算它的成本。
难道不能同时运行所有 500 个任务,因为它们不相互依赖吗?
简而言之,如果您有 500 个内核 ( CPU ) ,可以。
在线程之间切换上下文是一个非常昂贵的过程,并且涉及暂停当前线程,这就是为什么每个 CPU 运行一个线程更有效的原因。
从 C# 4.0 开始,您可以使用任务并行库和并行 LINQ (PLINQ),它简化了 .NET Framework 中的并行编程。
// IEnumerable<MyClass> items = ...
var results = items
// Enables parallel execution of the query
.AsParallel()
// Specifies the method for creating values
.Select(item => Calculate(item))
// Waits for calculating all the values and returns the result (as an array)
.ToArray();
您可以在此处查看示例: 如何:编写简单的 Parallel.ForEach 循环
你能启动 500 个线程吗 - 是的。他们会同时运行吗?不。话虽如此,不幸的是,要使用的最佳线程数是一个比每个内核线程更复杂的问题。
例如,英特尔处理器的每个内核有两个执行管道(称为 u 和 v),允许乱序处理,根据条件,可以比顺序处理相同的两条指令更快地执行两条指令。问题是执行管道确实在核心内共享一些资源。他们分享:
缓存、分支预测资源、指令获取和解码以及执行单元。
这意味着执行两条指令的效率取决于缓存未命中和分支预测未命中等因素。优势在于指令在等待高延迟操作时阻塞(例如,在高速缓存未命中时将内存内容提取到高速缓存中),如果另一条管道中有另一条指令,则可以在等待时处理它。这绝对不会比两个独立的内核快,但通常比顺序指令处理更快(平均快大约 25%)。
要记住的另一件事是,操作系统还需要处理器上的一些时间来执行。Microsoft 对高效处理的最大线程数的建议是每个逻辑核心 25 个线程(没有超线程的每个物理核心有 1 个逻辑核心,有 HT 的每个物理核心有 2 个)(这是 IIS 中每个核心的默认最大线程数设置)。然而,应该注意的是,这是一个“经验法则”。找到真正最优的唯一方法是在给定的软件/硬件设置上进行测试。然而,硬件优化在实践中并不实用,也不推荐,因此需要“经验法则”。