Parallel.For在VB.NET中给出了数组外部索引的索引

时间:2012-09-23 00:33:59

标签: .net vb.net

我有这段代码:

noObjs = 0
Dim oName As String
Dim i As Integer
Dim tripleIndex As Integer = 0
Do While sr.Peek() <> -1
   readCSV = sr.ReadLine.Split(sepChar(0))
   If readCSV.Length >= 3 Then
       oName = readCSV(0)
       For i = noObjs - 1 To 0 Step -1
           If oName = objNames(i) Then
               obIndOfTriple(tripleIndex) = i
               Exit For
           End If
       Next i
       If i = -1 Then
           objNames(noObjs) = oName
           obIndOfTriple(tripleIndex) = noObjs
           noObjs += 1
       End If
   End If
   tripleIndex += 1
Loop
sr.Close()

我正试图并行化:

noObjs = 0
Dim oName As String
Dim i As Integer
Dim tripleIndex As Integer = 0
Dim allData() As String = File.ReadAllLines(in_file)
Parallel.For(0, allData.Count, Sub(k)
                               readCSV = allData(k).Split(sepChar(0))
                               If readCSV.Length >= 3 Then
                                   oName = readCSV(0)
                                   For i = noObjs - 1 To 0 Step -1
                                       If oName = objNames(i) Then
                                           obIndOfTriple(tripleIndex) = i
                                           Exit For
                                       End If
                                   Next i
                                   If i = -1 Then
                                       objNames(noObjs) = oName
                                       obIndOfTriple(tripleIndex) = noObjs
                                       noObjs += 1
                                   End If
                               End If
                               tripleIndex += 1
                               End Sub)

但是,我得到一个“索引超出了数组的范围”:

If oName = objNames(i) Then

我还应该在这里提一下objNames()和obIndOfTriple()是全局声明的(具有固定大小)。 从一些搜索,我知道这与线程安全有关,虽然我仍然是并行的新手。 有人能指出我正确的方向吗? 感谢。

2 个答案:

答案 0 :(得分:3)

看来你正在寻找独特的字符串。

而不是蛮力

For i = noObjs - 1 To 0 Step -1
   If oName = objNames(i) Then
   obIndOfTriple(tripleIndex) = i
Exit For

尝试

Dictionary<String,Int32> 

和ContainsKey

字典有快速查找

This page has an example of locking in parallel。但不确定它是你需要的锁类型。

答案 1 :(得分:1)

问题的关键在于您有多个线程访问共享资源而不同步对这些资源的访问,从而引入竞争条件。

例如,考虑与noObjs相关的objNames。我怀疑您希望noObjs始终反映objNames中实际项目的数量。现在假设你有两个线程同时达到objNames(noObjs) = oName,那时noObjs是4。一个线程会将值写入objNames(4),然后另一个线程将立即覆盖它。第一个线程尚未到达增量noObjs的行!此外,当两个线程都执行noObjs += 1时,noObjs将为6,但noObjs(5)中不存储任何内容。这不是您所看到的异常的确切情况,但它是实施脆弱性的另一个症状。

在每个线程执行的代码中,您需要确保每个线程都有自己的可变空间来使用。通过让objNamesobjIndOfTriple成为二维数组,可以做到这一点。第一个维度是循环迭代,k,第二个维度是该迭代的数组索引。同样,noObjs将是一个数组,noObjs(k)将是与循环索引objNames关联的k数组中的元素数。

从技术上讲,这应该可行,但是在执行objNames之后,你需要将Parallel.For从一堆小数组合并到一个大数组中 - 基本上完成map-reduce的实现图案。

如果您确实完成了所有实现,那么您可能需要查看性能。您正在并行处理单行输入,并且从代码中看不出您为每一行做了很多工作。换句话说,逐行并行化,实际上可能会比按顺序完成后增加更多的开销。如果你有1000行,你实际上要求同时运行1000个小任务,因此管理任务变得比实际执行更多。现在,TPL可以根据它认为最好的方式决定是否真正并行做某事,这样可以减轻性能损失。