在 IEnumerable 上使用 AsParallel - 它是不是有任何并行性的好处?
Posted
技术标签:
【中文标题】在 IEnumerable 上使用 AsParallel - 它是不是有任何并行性的好处?【英文标题】:Using AsParallel on an IEnumerable - Will it have any benefit of parallelism at all?在 IEnumerable 上使用 AsParallel - 它是否有任何并行性的好处? 【发布时间】:2020-09-18 22:44:49 【问题描述】:IEnumerable<char> GetChars()
int i = int.MinValue;
while (i++ < int.MaxValue)
yield return (char)('A' + (i % 26));
将AsParallel
应用于上述可枚举字符有什么好处吗?
GetChars().AsParallel().REST_OF_THE_QUERY
因为,据我所知,要在许多线程上并行工作,需要为并行可用的不同线程对数据进行分区。但是这里我觉得枚举器会是一个瓶颈,因为它不能并行运行?
AsParallel
是否能够从该枚举器并行获取数据并利用多线程的优势?
【问题讨论】:
@GSerg 会 AsParallel 影响原始的 GetChar 函数,我认为不会,因为还没有要分区的枚举,一旦返回 GetChars 结果并调用下一个枚举器,就会发生分区,我我对吗? @Munzer 不,该函数是一个枚举器,它不返回结果,它返回一个枚举器,当你开始枚举它时就会开始产生结果。 @GSerg 这让我很困惑,因为文档显示为The AsParallel extension method binds the subsequent query operators, in this case ....
。这在他们的示例中被附加到 Enumerable.Range() 的枚举器函数中。
【参考方案1】:
关于查询:
GetChars().AsParallel().REST_OF_THE_QUERY
REST_OF_THE_QUERY
将被并行化。 GetChars
不会被并行化,将在当前线程中独占运行。 AsParallel
将其后的内容并行化(只要每个后续运算符返回 ParallelQuery
)。它不会并行化之前的内容。
更新: GSerg 在 cmets 中指出,GetChars().AsParallel()
当前线程 ID 在 GetChars
内部不断变化,尽管它似乎涉及一些锁定,因为没有两个线程进入GetChars
同时。我的实验与这些观察结果相符。这意味着 PLINQ 库不能用于查询需要线程关联的数据源。例如下面的代码在 WinForms 中抛出异常:
private void Button1_Click(object sender, EventArgs e)
Control.CheckForIllegalCrossThreadCalls = true;
int count = GetHandles().AsParallel().Count();
MessageBox.Show($"Controls: count");
private IEnumerable<IntPtr> GetHandles()
foreach (Control control in this.Controls)
yield return control.Handle;
InvalidOperationException:跨线程操作无效:控件“Button1”从创建它的线程以外的线程访问。
没有.AsParallel()
,不会抛出异常。
【讨论】:
一个简单的实验表明,GetChars().AsParallel()
System.Threading.Thread.CurrentThread.ManagedThreadId
在 GetChars
内部不断变化,并且对 GetChars
的调用以获取新元素与相应 REST_OF_THE_QUERY
的执行相互关联对于已经获取的元素。但是似乎确实涉及一些锁定,因为似乎没有两个线程同时进入GetChars
。
@GSerg 你是对的。我应该在回答之前测试它!以上是关于在 IEnumerable 上使用 AsParallel - 它是不是有任何并行性的好处?的主要内容,如果未能解决你的问题,请参考以下文章
C#- 在任务异步调用上返回 IEnumerable<object>