Parallel.ForEach每次都会给出不同的结果

时间:2013-04-05 12:28:08

标签: vb.net parallel-processing task-parallel-library parallel.foreach

请帮我将以下循环转换为并行循环。我尝试使用Parallel.ForEach和ConcurrentBag而不是HashSet,但是,每次不同的结果时,“匹配”都会返回。

我无法弄明白......是否因为线程安全问题?

关键字列表包含大约500个唯一字符串,每个字符串长度为1-3个字。

项目包含约10000项。

原始代码:

    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

尝试将其转换为

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

1 个答案:

答案 0 :(得分:2)

是的,您的代码当然不是线程安全的。使用线程安全的集合不会使您的代码自动进行线程安全,您仍然需要正确使用它们。

你的问题是在Contains()完成之后但在一个线程上调用Add()之前,Add()可以在另一个线程上调用(同样可能也会发生 Contains()执行。)

您需要做的是:

  1. 使用锁定(这意味着您不再需要使用线程安全集合);或
  2. 使用ConcurrentHashSet之类的内容。 .Net中没有这样的类,但您可以使用ConcurrentDictionary代替(即使它不完全符合您的需求)。您可以执行Contains(),而Add()只是因为Matched.TryAdd(Item, True)需要一些价值,而不是您TrueConcurrentDictionary的来电。