C#

时间:2017-03-22 12:19:48

标签: c#-4.0

我对C#中的Parallel.Foreach有疑问。我是多线程的新手,并且从一个月开始学习它。我正在使用Foreach循环,在该foreach循环中,我找到整数列表的平均值,并将每个平均值添加到一个cuncurrent包中。但是我面临的问题并不是所有迭代的结果都会被添加。我的列表中有10个条目,但是我添加的cuncurrent包在foreach循环结束时的条目少于10个。任何人都可以让我知道我做错了什么。

以下是我的代码:

static void Main(string[] args)
        {
            List<List<int>> intList = new List<List<int>>();
            List<int> ints = new List<int>();
            Random rand = new Random();
            for (int k = 1; k <= 10; k ++)
            {
                ints.Clear();
                for (int i = 0; i < 10000000; i++)
                {
                    ints.Add(rand.Next(10000000));
                }
                List<int> copy = new List<int>(ints);
                intList.Add(copy);
            }
            ConcurrentBag<double> results = new ConcurrentBag<double>();
            Parallel.ForEach<List<int>, double>(intList,
                () => 0,
                (eachIterationList, pls, threadLocal) =>
                {
                    threadLocal = eachIterationList.Average();
                    return threadLocal;
                },
                    (result) =>
                    {
                        lock (results)
                        {
                            results.Add(result);
                        }
                    });
            Console.WriteLine("No of results in results variable: {0}", results.Count);
            Console.ReadLine();
        }

结果变量在写入控制台时包含的元素少于10个我认为应该具有的元素。

2 个答案:

答案 0 :(得分:0)

为什么要锁定结果ConcurrentBag?做这样简单的工作:

        Parallel.ForEach(intList,
            list =>
            {
                results.Add(list.Average());
            });

锁定结果并不能保证您的商品顺序正确。 如果您希望两者都是同步的,请改用:

List<double> results = new List<double>(Enumerable.Repeat(0.0d, intList.Count));
Parallel.For(0, intList.Count,
(i) =>
{
   results[i] = intList[i].Average();
});

或使用.ForEach():

List<double> results = new List<double>(Enumerable.Repeat(0.0d, intList.Count));
Parallel.ForEach(intList,
    (item, loop, i) =>
    {
        results[(int)i] = item.Average();
    });

答案 1 :(得分:0)

您可以看到本地最终委托在每个用于处理Parallel.ForEach的任务的最终操作上运行。每次都可以是不同的数字。因此,如果您修改下面列出的代码,您将看到用于列表迭代的任务数与执行最终操作的任务数相同。最终授权代表的用途与您的需要不同。

您需要了解.NET中的线程和任务之间的区别。 当你使用lock添加到ConcurrentBag时你的代码也是错误的,因为它已经支持多线程添加到集合而你不需要锁定。

 List<List<int>> intList = new List<List<int>>();
        List<int> ints = new List<int>();
        Random rand = new Random();
        for (int k = 1; k <= 10; k++)
        {
            ints.Clear();
            for (int i = 0; i < 10000000; i++)
            {
                ints.Add(rand.Next(10000000));
            }
            List<int> copy = new List<int>(ints);
            intList.Add(copy);
        }
        HashSet<int?> resultTaskIds = new HashSet<int?>();
        HashSet<int?> iterationTaskIds = new HashSet<int?>();
        ConcurrentBag<double> results = new ConcurrentBag<double>();
        Parallel.ForEach<List<int>, double>(intList,
            () => 0,
            (eachIterationList, pls, threadLocal) =>
            {
                iterationTaskIds.Add(Task.CurrentId);

                return eachIterationList.Average();
            },
                (result) =>
                {
                    resultTaskIds.Add(Task.CurrentId);
                    results.Add(result);
                });