2

다음 루프를 병렬 루프로 변환하는 데 도움을주십시오. 나는 Parallel.ForEach와 ConcurrentBag를 HashSet 대신에 사용하려했지만, 매치 된 것은 매번 다른 결과를 반환한다는 것이다.Parallel.ForEach는 매번 다른 결과를 나타냅니다

알아낼 수 없습니다 ... 스레드 안전 문제 때문입니까?

키워드 목록에는 길이가 각각 1-3 단어 인 약 500 개의 고유 문자열이 있습니다.

항목에는 약 10000 개의 항목이 포함되어 있습니다.

원래 코드 :

Dim Items As IEnumerable(Of Item) = Db.Items.GetAll 

Dim Keywords As HashSet(Of String) 
Dim Matched As Concurrent.ConcurrentBag(Of Item) 

Threading.Tasks.Parallel.ForEach(Of Item)(Items, Sub(Item) 
    For Each Keyword In Keywords 
     If Regex.IsMatch(Item.Title, String.Format("\b{0}\b", Keyword), RegexOptions.IgnoreCase Or RegexOptions.CultureInvariant) Then 
      If Not Matched.Contains(Item) Then 
      Matched.Add(Item) 
      End If 
     Continue For 
     End If 
    Next 
End If 

답변

2

예로 변환하는

Dim Items As IEnumerable(Of Item) = Db.Items.GetAll 

    Dim Keywords As HashSet(Of String) 
    Dim Matched As HashSet(Of Item) 

    For Each Item In Items 

     For Each Keyword In Keywords 

      If Regex.IsMatch(Headline, String.Format("\b{0}\b", Keyword), RegexOptions.IgnoreCase Or RegexOptions.CultureInvariant) Then 
       If Not Matched.Contains(Item) Then 
        Matched.Add(Item) 
       End If 

      End If 

     Next 

    Next 

시도, 코드는 확실히 스레드로부터 안전하지 않습니다. 쓰레드에 안전한 콜렉션을 사용한다고해서 코드가 자동적으로 쓰레드에 안전 해지는 것은 아니며 여전히 올바르게 사용해야한다.

귀하의 문제는 하나 개의 스레드에서 호출 Add()Contains() 완료된 후하지만 전에, Add() 다른 스레드에서 호출 할 수 있습니다 (같은 가능성도 Contains() 동안 실행하는 일이 일어날 수)이다.

당신이 필요가있는 무엇을하는 것입니다 :

  1. 사용 잠금 (이것은 더 이상 스레드 안전 수집을 사용할 필요가 없음을 의미합니다) 또는
  2. ConcurrentHashSet과 같은 것을 사용하십시오. .NET에는 이러한 클래스가 없지만 정확히 (필요에 맞지 않더라도) ConcurrentDictionary을 사용할 수 있습니다. Contains()으로 전화 한 다음 Add()으로 전화하는 대신 을 입력 할 수 있습니다. ConcurrentDictionary에 값이 필요하기 때문에 True이있는 것입니다.
+0

이 두 샘플을 다른 방법으로 발견했습니다. 변경하는 데 지쳐 있었지만 이러한 샘플과 같은 통합 대신 컬렉션 및 개체에서 작동하지는 못했습니다. 스빅, 제 생각에는 이것들이 효과가 있다고 생각합니까? http://technet.microsoft.com/subscriptions/dd460699.aspx http://tipsandtricks.runicsoft.com/CSharp/ParallelClass.html – jjarv

관련 문제