Тупик в Parallel.Foreach при использовании ExecuteNonQuery? - PullRequest
1 голос
/ 08 мая 2020

Я столкнулся с ошибкой взаимоблокировки при использовании Parallel.Foreach. У меня есть 1000 записей в datatable, и i'hv создал 5 потоков для его обработки. но когда я запускаю это консольное приложение, то после обработки некоторых записей он создает тупик, и никакие другие записи не будут обрабатываться. Вот мой код:

Parallel.ForEach(dt1.AsEnumerable(), new ParallelOptions { MaxDegreeOfParallelism = 5 }, dr =>
{
    cmd1.CommandText = $"Update AuditMessage set Status=1" +
        $" where SXAEASCoreAuditMessageID ='{Convert.ToString(dr["AuditMessageID"])}' ";
    cmd1.CommandType = CommandType.Text;
    cmd1.Transaction = trans;
    cmd1.ExecuteNonQuery();                          
});

1 Ответ

2 голосов
/ 08 мая 2020

Почему он блокируется?

Вероятно, ваша проблема заключается не в параллелизме базы данных, а в параллелизме объекта cmd1, который вы используете для каждого потока.

Вам необходимо создать новую команду SqlCommand для каждого потока или на каждой итерации.

Parallel.ForEach(dt1.AsEnumerable(), new ParallelOptions { MaxDegreeOfParallelism = 5 }, dr =>
    {
                  using(var cmd = new SqlCommand(connection))
                  {
                     cmd.CommandText = $"Update AuditMessage set Status=1 where SXAEASCoreAuditMessageID ='{Convert.ToString(dr["AuditMessageID"])}' ";
                     cmd.CommandType = CommandType.Text;
                     cmd.Transaction = trans;
                     cmd.ExecuteNonQuery();
                  }                          
    });

некоторые основы блокировки строк / таблиц.

В случае, если вы делаете это на SQL сервере, вы создаете больше накладных расходов, чем скорость этой параллельной обработки. Каждая измененная строка будет заблокирована СУБД, и в конечном итоге, когда накладные расходы станут высокими, начнется блокировка таблицы, в результате чего ваши потоки все равно будут работать последовательно.

поэтому забудьте о parallel.foreach здесь, и пусть база данных выполняет оптимизацию эффективности

Вы можете выбрать AuditMessageIds в списке. Затем разрежьте его на части по 100 или около того, а затем сделайте более умный запрос на обновление, например запрос, который выполняет массовое обновление до статуса 1 ..

where SXAEASCoreAuditMessageID IN ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...