1

私はこのコードの塊を持っています:

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() がグローバルに (固定サイズで) 宣言されていることにも言及する必要があります。いくつかの検索から、これはスレッドセーフに関係していることを理解していますが、私はまだ並列処理の初心者です。誰かが私を正しい方向に向けることができますか? ありがとう。

4

2 に答える 2

3

一意の文字列を探しているようです。

力ずくではなく

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

試す

Dictionary<String,Int32> 

およびContainsKey

ディクショナリは高速検索

このページには、並列ロックの例があります。しかし、それが必要なタイプのロックかどうかはわかりません。

于 2012-09-23T14:15:35.833 に答える
1

問題の核心は、それらのリソースへのアクセスを同期せずに共有リソースにアクセスする複数のスレッドがあり、それによって競合状態が発生することです。

例えば、 とnoObjsの関係で考えてみましょうobjNamesnoObjsに実際のアイテムの数を常に反映させたいと思われますobjNamesobjNames(noObjs) = oNameここで、同時に到達する 2 つのスレッドがあり、同時にnoObjs4 つあるとします。1 つのスレッドが値を書き込むobjNames(4)と、別のスレッドがすぐに上書きします。最初のスレッドは、まだインクリメントする行に達しnoObjsていません! さらに、両方のスレッドが実行されるとnoObjs += 1noObjsは 6 になりますが、 には何も格納されませんnoObjs(5)。これは、あなたが見ている例外の正確なケースではありませんが、実装の脆弱性の別の症状です。

各スレッドが実行するコードでは、各スレッドが操作する独自の変数スペースを確保する必要があります。2 次元配列にすることでそれを行うことができます。最初の次元はループの反復であり、2 番目の次元はその反復のためだけの配列へのインデックスになります。同様に、は配列になり、はループ インデックス に関連付けられた配列内の要素の数になります。objNamesobjIndOfTripleknoObjsnoObjs(k)objNamesk

技術的にはうまくいくはずですが、基本的に map-reduce パターンの実装を完了するためにobjNames、一連の小さな配列を 1 つの大きな配列に結合する必要があります。Parallel.For

すべてを実装した場合は、パフォーマンスを確認することをお勧めします。単一行の入力の処理を並列化していますが、コードからは、各行に対して多くの作業を行っているようには見えません。言い換えれば、行ごとに並列化すると、実際には、順次実行した場合よりも多くのオーバーヘッドが追加される可能性があります。1000 行ある場合、基本的には 1000 個の小さなタスクを同時に実行するように要求することになるため、実際にタスクを実行するよりもタスクを管理する方が手間がかかります。現在、TPL は、パフォーマンスへの影響を軽減できるように、最善と思われることに基づいて実際に何かを並行して実行するかどうかを決定する場合があります。

于 2012-09-23T02:42:34.223 に答える