2010-05-02 6 views
6

Parallel for 루프와 List에 관련된 문제가 있습니다. 문제는 동일한 코드가 서로 다른 시간에 서로 다른 출력을 생성 할 수 있다는 것입니다. 아래에 몇 가지 테스트 코드를 설정했습니다. 이 코드에서는 10,000 개의 int 값 목록을 만듭니다. 값의 1/10은 0이 될 것이고 값의 1/10은 1이 될 것입니다. 값의 1/10까지 9가됩니다.병렬 For 루프 - 목록에 추가 할 때의 문제

이 목록을 설정 한 후에는 Parallel for 루프 그 목록을 반복합니다. 현재 숫자가 0이면 새 목록에 값을 추가합니다. Parallel for 루프가 완료되면 목록의 크기를 출력합니다. 크기는 항상 1,000이어야합니다. 대부분의 경우 정답이 주어집니다. 그러나 내가 본 3 개 가능한 잘못된 결과가 발생합니다

  1. 목록의 크기 미만 1,000
  2. IndexOutOfRangeException가 발생입니다 doubleList.Add(0.0);
  3. ArgumentException가 발생 doubleList.Add(0.0);

@ 메시지 @ 주어진 ArgumentException에 대해 다음과 같았습니다 : Destination array was not long enough. Check destIndex and length, and the array's lower bounds.

오류의 원인은 무엇입니까? 에스? 이것은 .Net 버그입니까? 이런 일이 일어나지 않도록 내가 할 수있는 일이 있습니까?

직접 코드를 사용해보십시오. 오류가 발생하지 않으면 몇 번 시도하십시오. 또한 단일 코어 컴퓨터를 사용하는 경우에는 오류가 표시되지 않습니다.

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(); 
     } 
    } 
} 
+1

.NET 버그 또는 사용자 코드의 버그는 무엇입니까? –

+0

디버깅 규칙 # 1 : 버그는 항상 코드에 있습니다. 당신은 이것의 * 제목 *에서 무엇이 잘못되었는지를 알 수 있습니다. – Aaronaught

답변

18

나는 System.Collections.Generic.List 당신이 두 개의 서로 다른 스레드에서 동시에 Add하려고하면, 일이 잘못 것을 의미, 스레드 안전하지 않습니다 기대합니다. 아 아 맞아, docs에서 그렇게 말합니다.

당신은 여러 가지 방법으로이를 방지 할 수 :

  • 사용 스레드가 추가 할 수있는 집합 형
  • 잠금 추가하기 전에 (닷넷의 일부 new ones 4.0이 있습니다)
  • ...

이를 컬렉션에 대한 스레드 로컬 저장소를 사용하고, 마지막

  • 에 병합 데이터 병렬 코드로 만나는 전형적인 문제입니다.

  • +1

    +1. System.Collections.Generic.List는 스레드로부터 안전하지 않습니다. .NET Framework 4.0 –

    +0

    +1에는 다른 스레드보다 훨씬 빠른 세 번째 제안에 대한 스레드로부터 안전한 컬렉션이 있습니다. – tster

    +0

    @tster - 예, Parallel이 있습니다. 전략에 도움이되는 과부하 : http://msdn.microsoft.com/en-us/library/dd783586.aspx – Brian

    관련 문제