2012-09-23 107 views
1

我有這一塊的代碼:的Parallel.For給index數組的邊界之外在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() 

而且我想parallelise這樣:

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()聲明全球(具有固定大小)。 從一些四處搜索,我明白,這與線程安全有關,儘管我仍然是一個並行的新手。 任何人都可以指向正確的方向嗎? 謝謝。

回答

1

問題的癥結在於您有多個線程訪問共享資源,而無法同步對這些資源的訪問並因此引入爭用條件。

例如,考慮與objNames有關的noObjs。我懷疑你想要noObjs始終反映objNames中的實際項目數。現在假設您有兩個線程同時到達objNames(noObjs) = oName,並且noObjs當時是4。一個線程會將值寫入objNames(4),然後另一個線程將立即覆蓋它。第一個線程還沒有到達線增加noObjs呢!此外,當兩個線程都執行noObjs += 1時,noObjs將爲6,但您將沒有任何內容存儲在noObjs(5)中。這不是你所看到的例外情況,但這是實施脆弱性的另一個症狀。

在每個線程執行的代碼中,您要確保每個線程都有自己的可變空間來處理。你可能通過使objNamesobjIndOfTriple是二維數組來做到這一點。第一個維度將是循環迭代,k,第二個維度將是該迭代中數組的索引。同樣,noObjs將是一個數組,並且noObjs(k)將是objNames數組中與循環索引k關聯的元素的數量。

從技術上說應該可以工作,但是在執行Parallel.For之後,您需要將objNames從一堆小陣列合併爲一個大陣列 - 實質上完成了map-reduce模式的實現。

如果你確實得到了所有的實現,你可能想看看性能。您正在平行處理一行輸入,並且從沒有出現的代碼開始,您對每行都做了很多工作。換句話說,按照您的要求逐行對其進行並行化,實際上可能會比按順序完成更多的開銷。如果你有1000行,你基本上要求1000個小任務同時運行,所以管理任務比實際執行更多的工作。現在,第三方物流可能會根據自己認爲最好的做法來決定是否真的做一些事情,這樣可以緩解業績衝擊。

+0

感謝您的回覆。我懷疑是在跑步與串行實現相比,1000行會導致開銷。問題是noObjs在一種情況下可以是1000,在另一種情況下可以是1000000。爲了彌補這一點,我想如果noObjs <= 100000,例如一個串行實現,併爲任何更高的並行。不幸的是,並行(通常和.NET)對我來說是一個全新的篇章。 – globetrotter

+0

實際上,隨着行數的增加,問題變得更糟,因爲您現在正在切換更多的對象,每個對象都沒有做很多工作。你只能真正的並行化你所擁有的CPU數量。試驗每個並行任務實際上可以有多行......所以如果你有1000個可能每個都有250行要做。再次,框架有一些智慧來確定何時並行化太昂貴,但我不確定它是什麼/何時觸發的。 –

+0

btw你會建議作爲我發佈的系列實現的優化嗎? – globetrotter

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。但不知道這是你需要的鎖的類型。

+0

您好Blam,我已經實現了您的解決方案,性能從大約30秒(我擁有一些文件)提高到了幾毫秒。感謝您的建議! – globetrotter

+0

30秒到幾毫秒,甚至不值+1 +1 – Paparazzi

+0

它說我的聲望太低:) – globetrotter

相關問題