English 中文(简体)
.NET 4.0 和 4.5
原标题:PLINQ ForAll broken in .NET 4.0 and 4.5

我试图想出一种方法来加速以最快的方式将列表中包含的大量物体组合起来。 希望利用 PLINQ 我尝试过, 但这不是一个线索安全的解决办法 。 我在 VS2010 和 VS11Beta 中测试了 4. 0 和 4. 5 和 4. 5 。 这是我的试样应用程序。 如果您在 1500 之间更改 BlowUp () 通常会有效 。 在500 轮子到达轨道后, 它会在许多地方失效 。 有人知道最快的方法解决这个问题吗? (多层阵列+ PLINQ? )

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PLinqBlowsUp
{
class Program
{
    static void Main(string[] args)
    {
        BlowUp(5000);
    }

    private static void BlowUp(int blowupNum)
    {
        try
        {
            var theExistingMasterListOfAllRowsOfData = new List<List<KeyValuePair<string, dynamic>>>();

            //Add some test data
            Enumerable.Range(0, blowupNum).AsParallel().ForAll(row => theExistingMasterListOfAllRowsOfData.Add(AddRowToMasterList(row)));


            var aNewRowOfData = new List<KeyValuePair<string, dynamic>>();
            //Add some test data
            var column = new KeyValuePair<string, dynamic>("Title", "MyTitle");
            aNewRowOfData.Add(column);

            var anotherNewRowOfData = new List<KeyValuePair<string, dynamic>>();
            //Add some test data
            var columnA = new KeyValuePair<string, dynamic>("Date", DateTime.Now);
            var columnB = new KeyValuePair<string, dynamic>("ImportantColumn", "ImportantData");
            var columnC = new KeyValuePair<string, dynamic>("VeryImportantColumn", "VeryImportantData");
            anotherNewRowOfData.Add(columnA);
            anotherNewRowOfData.Add(columnB);
            anotherNewRowOfData.Add(columnC);

            //Now the Problem
            aNewRowOfData.AsParallel().ForAll(anrod => theExistingMasterListOfAllRowsOfData.ForEach(temloarod => temloarod.Add(anrod)));
            anotherNewRowOfData.AsParallel().ForAll(anrod => theExistingMasterListOfAllRowsOfData.ForEach(temloarod => temloarod.Add(anrod)));

            //Test for number
            foreach (var masterRow in theExistingMasterListOfAllRowsOfData)
            {
                if (masterRow.Count != 7)
                    throw new Exception("BLOW UP!!!");
            }
        }
        catch (AggregateException ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    private static List<KeyValuePair<string, dynamic>> AddRowToMasterList(int row)
    {
        var columnA = new KeyValuePair<string, dynamic>("FirstName", "John" + row.ToString());
        var columnB = new KeyValuePair<string, dynamic>("LastName", "Smith" + row.ToString());
        var columnC = new KeyValuePair<string, dynamic>("Ssn", 123456789 + (row*10));

        var list = new List<KeyValuePair<string, dynamic>>();
        list.Add(columnA);
        list.Add(columnB);
        list.Add(columnC);
        return list;
    }
}
}
最佳回答

我看到两个问题。

  • You are calling Add on the theExistingMasterListOfAllRowsOfData instance from more than one thread without any attempt to synchronize access to it.
  • You are calling Add on the individual List<KeyValuePair<string, dynamic>> items from more than one thread without any attempt to synchronize them.

您可以使用 lock 来保护 Add 方法, 或者使用 ContropBag 方法。 但是, 这些选项都不是那么好 。 这里的问题是, 由于所有线条最终都会竞争同一锁, 无法将这种操作平行得非常好 。 我非常怀疑即使低锁 ContromBag 也最终会比您刚刚在 PLINQ 上划线并做了所有要开始的主线要慢 。

问题回答

这与 PLinq 无关 - 在 < code> List< T> 中添加一个项目根本不安全。 一个能降低性能的可行解决方案是引入锁定。 您通常想要做的是投射到一个由于您的 PLinq 语句而导致的 < 坚固 > new < / strong > 收藏中 - 与您所做的一样, 引入副作用, 与其说是Linq / 功能性编程的总体精神, 不如说是不符合Linq / 功能性编程的精神, 你可能会遇到麻烦( 如您所做的那样 ) 。

PLinq 无法替代写入线索安全代码 。 您对 < code> the existing MasterListofallRowsofData 的访问并不安全, 因为线索库的所有线索都可以访问它 。 您可以尝试锁定它, 这解决了我的问题 :

Enumerable.Range(0, blowupNum).AsParallel().ForAll(row => {
    lock (theExistingMasterListOfAllRowsOfData) {                 
        theExistingMasterListOfAllRowsOfData.Add(AddRowToMasterList(row));
    }
});

然而,锁门可能不是你们想要的东西,因为这会造成瓶颈。





相关问题
Manually implementing high performance algorithms in .NET

As a learning experience I recently tried implementing Quicksort with 3 way partitioning in C#. Apart from needing to add an extra range check on the left/right variables before the recursive call, ...

Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

How do I compare two decimals to 10 decimal places?

I m using decimal type (.net), and I want to see if two numbers are equal. But I only want to be accurate to 10 decimal places. For example take these three numbers. I want them all to be equal. 0....

Exception practices when creating a SynchronizationContext?

I m creating an STA version of the SynchronizationContext for use in Windows Workflow 4.0. I m wondering what to do about exceptions when Post-ing callbacks. The SynchronizationContext can be used ...

Show running instance in single instance application

I am building an application with C#. I managed to turn this into a single instance application by checking if the same process is already running. Process[] pname = Process.GetProcessesByName("...

How to combine DataTrigger and EventTrigger?

NOTE I have asked the related question (with an accepted answer): How to combine DataTrigger and Trigger? I think I need to combine an EventTrigger and a DataTrigger to achieve what I m after: when ...

热门标签