添加到列表时出现问题 - 并行循环 [英] Parallel For Loop - Problems when adding to a List

查看:173
本文介绍了添加到列表时出现问题 - 并行循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有涉及并行for循环,并添加到列表的一些问题。问题是,在同一code可以产生不同的输出在不同的时间。我已经建立了一些测试code以下。在这种code,我创建了10000 INT值的列表。 1的值的/第十将是0,值1 /第十将为1,所有的方式来为9的值的1/10日

在列表中设置了这个名单,我设置一个并行的循环迭代之后。如果当前的数字是0,我的值添加到一个新的列表。后的并行循环完成后,I输出列表的大小。大小应始终是1000。大部分时间,正确的答案给出。不过,我已经看到了3个可能不正确的结果出现:

  1. 列表的大小小于1000
  2. 的<一个href="http://msdn.microsoft.com/en-us/library/system.indexoutofrangeexception%28VS.71%29.aspx">IndexOutOfRangeException发生@ doubleList.Add(0.0);
  3. 在一个 ArgumentException的发生@ doubleList.Add(0.0 );

该消息给出的ArgumentException的是:目标数组不够长。检查destIndex和长度以及数组的下限。

这可能是造成的错误?这是一个.NET错误?有什么我可以做,以prevent这种情况的发生?

请尝试code自己。如果你没有得到一个错误,尝试了几次。请注意,使用的是单核机,你可能不会看到任何错误。

 使用系统;
使用System.Collections.Generic;
使用System.Threading.Tasks;

命名空间ParallelTest
{
    类节目
    {
        静态无效的主要(字串[] args)
        {
            名单&LT; INT&GT; intList =新的名单,其中,INT&GT;();
            名单&LT;双&GT; doubleList =新的名单,其中,双&GT;();

            的for(int i = 0; I&LT; 250;我++)
            {
                intList.Clear();
                doubleList.Clear();

                对于(INT J = 0; J&LT; 10000; J ++)
                {
                    intList.Add(十%10);
                }

                的Parallel.For(0,intList.Count,J = GT;
                {
                    如果(intList [J] == 0)
                    {
                        doubleList.Add(0.0);
                    }
                });

                如果(doubleList.Count!= 1000)
                {
                    Console.WriteLine(迭代的+ I +:列表大小=+ doubleList.Count);
                }
            }

            Console.WriteLine(\ñpreSS任意键退出。);
            Console.ReadKey();
        }
    }
}
 

解决方案

我希望System.Collections.Generic.List不是线程安全的,这意味着如果你试图同时添加从两个不同的线程,事情会出问题。是啊,它是这么说的文档

您可以prevent这种情况发生在许多方面:

  • 使用集合类型,允许线程增加(有一些新的在.NET 4.0中)
  • 锁定前要加
  • 使用线程本地存储的收藏,并在年底将其合并
  • ...

这些都是您遇到数据并行code非常典型的问题。

I am having some issues involving Parallel for loops and adding to a List. The problem is, the same code may generate different output at different times. I have set up some test code below. In this code, I create a List of 10,000 int values. 1/10th of the values will be 0, 1/10th of the values will be 1, all the way up to 1/10th of the values being 9.

After setting up this List, I setup a Parallel for loop that iterates through the list. If the current number is 0, I add a value to a new List. After the Parallel for loop completes, I output the size of the list. The size should always be 1,000. Most of the time, the correct answer is given. However, I have seen 3 possible incorrect outcomes occur:

  1. The size of the list is less than 1,000
  2. An IndexOutOfRangeException occurs @ doubleList.Add(0.0);
  3. An ArgumentException occurs @ doubleList.Add(0.0);

The message for the ArgumentException given was: Destination array was not long enough. Check destIndex and length, and the array's lower bounds.

What could be causing the errors? Is this a .Net bug? Is there something I can do to prevent this from happening?

Please try the code for yourself. If you do not get an error, try it a few times. Please also note that you probably will not see any errors using a single-core machine.

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

namespace ParallelTest
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> intList = new List<int>();
            List<double> doubleList = new List<double>();

            for (int i = 0; i < 250; i++)
            {
                intList.Clear();
                doubleList.Clear();

                for (int j = 0; j < 10000; j++)
                {
                    intList.Add(j % 10);
                }

                Parallel.For(0, intList.Count, j =>
                {
                    if (intList[j] == 0)
                    {
                        doubleList.Add(0.0);
                    }
                });

                if (doubleList.Count != 1000)
                {
                    Console.WriteLine("On iteration " + i + ": List size = " + doubleList.Count);
                }
            }

            Console.WriteLine("\nPress any key to exit.");
            Console.ReadKey();
        }
    }
}

解决方案

I expect that System.Collections.Generic.List is not thread-safe, meaning that if you try to concurrently Add from two different threads, things will go wrong. Ah yes, it says so in the docs.

You could prevent this from happening in a number of ways:

  • use a collection type that allows threadsafe adds (there are some new ones in .Net 4.0)
  • lock before you add
  • use thread-local storage for the collections, and merge them at the end
  • ...

These are very typical issues you encounter with data parallel code.

这篇关于添加到列表时出现问题 - 并行循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆