【问题标题】:Parallel.ForEach gives different results each timeParallel.ForEach 每次都会给出不同的结果
【发布时间】:2013-04-05 12:28:08
【问题描述】:

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

我想不通...是不是因为线程安全问题?

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

Items 包含大约 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

【问题讨论】:

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


    【解决方案1】:

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

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

    你需要做的是:

    1. 使用锁定(这意味着您不再需要使用线程安全集合);或
    2. 使用类似ConcurrentHashSet 的东西。 .Net 中没有这样的类,但您可以改用ConcurrentDictionary(即使它不完全符合您的需求)。您可以调用Matched.TryAdd(Item, True),而不是调用Contains(),然后调用Add(),其中True 存在只是因为ConcurrentDictionary 需要一些价值。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-12
    • 2021-07-12
    • 2018-05-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多