在 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.ManagedThreadIdGetChars 内部不断变化,并且对 GetChars 的调用以获取新元素与相应 REST_OF_THE_QUERY 的执行相互关联对于已经获取的元素。但是似乎确实涉及一些锁定,因为似乎没有两个线程同时进入GetChars @GSerg 你是对的。我应该在回答之前测试它!

以上是关于在 IEnumerable 上使用 AsParallel - 它是不是有任何并行性的好处?的主要内容,如果未能解决你的问题,请参考以下文章

IEnumerable 和 IQueryable

C#- 在任务异步调用上返回 IEnumerable<object>

IEnumerable & IEnumerator

使用 OrderByDescending 每一步返回 IEnumerable<T> 列表集合中的最大值

在List之间自由转换 和IEnumerable

IEnumerable的几个简单用法