0

В многопотоке делаю гет-запросы. Результат пихаю в список. Дальше в монопольном режиме хочу запихнуть данные в БД. Почему то lock не даёт монопольный доступ к InsertRowsToDB, так как у меня в БД дублируются данные.

var rows = new List<string>();
Object locker = new Object();
Parallel.For(0,urls.Count, new ParallelOptions { MaxDegreeOfParallelism = 100}, (i) =>
{
   var data = GetRequest(urls[i]);
   lock(locker)
     {
       rows.Add(data);
   if (rows.Count&gt;=100)
   {
       InsertRowsToDB(rows); 
       rows.Clear();
   }
 }

});

Radzhab
  • 3,772
  • 2
    Вам точно надо многопоток, а не асихронщину? – A K Oct 13 '20 at 04:43
  • 1
    Проблема за пределами показанного кода. Виноват здесь не лок, а скорее сам метод InsertRowsToDB, возможно он асинхронный. – aepot Oct 13 '20 at 05:23
  • 1
    Например можно пофиксить вот так InsertRowsToDB(rows.ToList()); - передавать копию списка, чтобы гарантировать, что она не будет модифицирована, пока идет запись. – aepot Oct 13 '20 at 05:31
  • @AK в многопотоке идут гет запросы для ускорения – Radzhab Oct 13 '20 at 05:34
  • "так как у меня в БД дублируются данные" - ну и что? –  Oct 13 '20 at 05:43
  • @Igor урлов у меня 1к, данных в бд появляется 2-3к. Они дублируются – Radzhab Oct 13 '20 at 05:54
  • 2
    Покажите ваш метод InsertRowsToDB – Геннадий П Oct 13 '20 at 06:21
  • 1
    Но у вас же по логике и после цикла должен быть вызов InsertRowsToDB(rows), иначе вы потеряете часть данных (до 99 записей). Приводите уж весь код, имеющий отношение к делу. – CrazyElf Oct 13 '20 at 06:57
  • 1
    в многопотоке идут гет запросы для ускорения для асинхронныйх вызовов не нужен многопоток, но они вполне могут выполняться одновременно. – aepot Oct 13 '20 at 08:12

1 Answers1

2

Если не вдаваться в подробности того, что вероятно у вас неверно простроена работа по сети и с БД, то можете попробовать вот такой вариант решения.

var rows = new List<string>();
Object locker = new Object();
Parallel.For(0,urls.Count, new ParallelOptions { MaxDegreeOfParallelism = 100}, (i) =>
{
   var data = GetRequest(urls[i]);
   lock(locker)
   {
       rows.Add(data);
   if (rows.Count&gt;=100)
   {
       InsertRowsToDB(rows); 
       rows = new List&lt;string&gt;();
   }

} }); InsertRowsToDB(rows);

В этом случае, список, переданный в метод InsertRowsToDB не будет изменен после передачи.

А происходит это потому что возврат из метода InsertRowsToDB происходит раньше, чем сам метод завершит работу. Скорее всего, он асинхронный, либо содержит асинхронные вызовы, завершения которых вы не ожидаете, а выполняете возврат из метода.

aepot
  • 49,560