добавить строки в таблицу данных с помощью parallel.for - PullRequest
1 голос
/ 13 июля 2010

У меня есть этот саб:

Private Sub error_out(ByVal line As Integer, ByVal err_col As Integer, ByVal err_msg As String)

            Dim ln = t_erori.Rows.Add
            ln.Item(0) = line
            ln.Item(err_col) = err_msg
            ln.Item(3) = err_col
    End Sub

Это вызывается несколькими функциями, работающими в цикле параллельного .for.

Проблема в том, что иногда (совершенно случайно) я получаю сообщение об ошибке:

Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index

в строке Dim ln = t_erori.Rows.Add.

Я подозреваю, что это потому, что он пытается добавить одну и ту же строку дважды. Как я могу сделать эту работу? Или какой еще метод я мог бы использовать для этого?

Мне нужна эта таблица данных, потому что мое приложение записывает туда некоторые результаты, но любой другой метод для сохранения результатов, который работает с parallel.for, будет в порядке.

Ответы [ 2 ]

2 голосов
/ 13 июля 2010

Это болезнь новых параллельных расширений. Вы можете легко написать небезопасный код. MSDN для DataTable говорит:

Резьба безопасности

Этот тип безопасен для многопоточных операции чтения. Вы должны синхронизировать любые операции записи.

Вы выполняете небезопасную операцию в нескольких потоках. Вы должны использовать lock или SpinLock (предпочтительно) или ReaderWriterLockSlim.

1 голос
/ 15 июля 2010

Наивный подход к исправлению этого заключается в том, чтобы обернуть все в блок SyncLock.

Private Sub error_out(ByVal line As Integer, ByVal err_col As Integer, ByVal err_msg As String) 

  SyncLock t_erori
    Dim ln = t_erori.Rows.Add 
    ln.Item(0) = line 
    ln.Item(err_col) = err_msg 
    ln.Item(3) = err_col 
  End SyncLock

End Sub 

Проблема в том, что вы эффективно сериализовали выполнение error_out, поскольку все потоки должны боротьсяза тот же замок.Конечным результатом является то, что это может закончиться работой медленнее, чем эквивалентная непараллелизированная версия.

Самый простой способ воспользоваться преимуществами потоков - делегировать всю операцию добавления строк в DataTable длярабочий поток и позволить основному потоку продолжить то, что он делал, а затем присоединить рабочий поток к основному потоку через Thread.Join, когда пришло время для основного потока запросить завершение операции.

...