Parallel.ForEach - 它在单核机器上运行吗?

20
我知道新的TPL(任务并行库)已经实现了Parallel.ForEach,使其能够与“显式并行性”一起工作。这意味着它不能保证您的委托将在多个线程中运行,而是检查主机平台是否有多个核心,如果是,则仅在核心之间分配工作(基本上每个核心1个线程)。
如果主机系统没有多个核心(越来越难找到这样的计算机),则会像“普通”的for each循环一样按顺序运行代码。相当酷的东西。
通常,我会执行以下操作,将我的长时间运行的操作放在来自ThreadPool的后台线程上:
ThreadPool.QueueUserWorkItem(new WaitCallback(targetMethod), new Object2PassIn() );

在主机计算机只有一个核心的情况下,TPL的Parallel.ForEach是否会自动将调用放在后台线程上?或者,我应该手动从后台线程调用任何TPL调用,这样如果我在单核计算机上执行,至少该逻辑将脱离GUI的分派线程?
我的担忧是,如果我让TPL负责所有这些工作,我希望确保如果它确定这是单核盒子,它仍然将在后台线程中编写Parallel.ForEach循环内的代码,就像我所做的那样,以不阻止我的GUI。

1
这只是一个快速的跟进:TPL太棒了!使用TPL调用进行一些小的调整,与“标准”方式相比,我能够使各种应用程序运行更快。我看到处理时间缩短了高达80%。微软在这方面真的做得很好 - 伟大的工作,伙计们。 - BonanzaDriver
5个回答

20
你的假设是不正确的。
Parallel.For 始终是一个阻塞调用。
即使计算机有多个核心,它仍将等待所有线程完成后才返回。
如果你不想冻结用户界面,你总是需要显式地调用线程池。

3
可以将其放入一个任务中,并使用 continuation 等待其完成,然后通知 UI。 - Claus Jørgensen

1

通过我使用Parallel.ForEach和Parallel.For循环的经验,我注意到顺序可能会是无序的,在实施之前您可能需要考虑这一点。

例如,基本for循环将产生:

Product 1 Product 2 Product 3 Product 4

并且并行循环可以产生(但不总是):

Product 3 Product 1 Product 2 Product 4

请记住这一点。


0

我认为如果您对实例/线程计数有确切的要求,您需要自己完成。我认为Parallel.ForEach类型的调用是为了声明性地涉及核心。我不确定,但我有一个隐秘的怀疑,它可能不适合做阻塞I/O(例如)的事情。


根据我所阅读的文档,它最初是为“处理器绑定”问题集而设计的。但这并不排除将其用于IO。事实上,让我认真看待TPL的原因是我有一个应用程序,大约执行了7,800个Web查询...我有一个双四核处理器盒子(3.0 GHz Xeons),在Windows 7 Ultimate 64位版上运行24GB RAM...那需要大约25到28分钟才能完成。还有一些下载HTML的额外处理,但你明白我的意思。我将其更改为TPL调用,只需<5分钟即可完成。 - BonanzaDriver

0

好问题。我认为即使只有一个核心,它仍然会生成一个线程。

我需要在单核心机器上运行测试。由于我没有这样的机器,我将使用虚拟机并将其环境CPU设置为1,看看Parallel ForEach会生成多少个线程。

您可能想阅读以下内容:

Parallel是否限制活动线程数


0

默认情况下,Parallel.ForEach 方法会在当前线程和 ThreadPool 线程上调用 body 委托¹。

如果您使用值 Environment.ProcessorCount 配置 MaxDegreeOfParallelism,它将使用当前线程以及来自 ThreadPoolEnvironment.ProcessorCount - 1 线程作为工作线程。 在单核计算机上,Environment.ProcessorCount1,因此在这种情况下仅使用当前线程。

如果您不配置MaxDegreeOfParallelism,则此设置的默认值为-1,表示无限并行。这实际上意味着ThreadPool将立即饱和。当ThreadPool饱和时,它开始弹出新线程以适应需求,速度约为每秒一个新线程²。拥有一个饱和的ThreadPool很少是理想的,如果有的话,我的建议是每次使用{{link1:Parallel}}系列的方法³时都要配置MaxDegreeOfParallelism

¹ 可以通过配置 TaskScheduler 选项来控制调用 body 的位置。找到适合特殊需求的 TaskScheduler(或编写自己的)并不容易。还要注意,调度程序的 MaximumConcurrencyLevel 影响(限制)最大并行度(链接)。
² 至少在我的四核机器上,.NET 6 是这样工作的。
³ 除了新的 Parallel.ForEachAsync API 外,它具有默认的 MaxDegreeOfParallelism 等于 Environment.ProcessorCount


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接