Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.88/8: Рейтинг темы: голосов - 8, средняя оценка - 4.88
109 / 52 / 16
Регистрация: 09.06.2021
Сообщений: 480

Ошибка в при заполнении Dictionary

09.06.2021, 18:47. Показов 1577. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Основной вопрос, почему ошибка?
Конечно нельзя под lock делать async, но это же правило для исключения взаимоблокировок?

Сервер выдает данные ордеров по запросам Rest и их изменения по WebSocket.
Чтобы всегда были актуальные данные, программа должна начать получать данные по WebSocket, накапливая их в , через 10 секунд сделать запросы Rest, продолжить получать данные по WebSocket до тех пор, пока sequence данного по WebSocket не станет больше sequence данного по Rest.
С этого момента данные Rest будут корректироваться с каждым данным по WebSocket.
Начал писать программку, но почему-то появляется ошибка.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
hashSetWorkForArbitrage = new(){ { "BCHSV-USDT" },{ "BCHSV-USDC" }, { "SNX-USDT" }, { "SNX-UST" },{ "EOS-USDT" }}
static ConcurrentDictionary<string, List<SocketOrderBook>> DicFirstListOrderBook = new();//по каждому символу хранит список значений поступающих  по WebSocket
public async Task FillOrderBookForForum(string message)
    {
      SocketOrderBook socketorderbook = JsonConvert.DeserializeObject<SocketOrderBook>(message);     
      var marketSymbol = socketorderbook.data.marketSymbol;
      lock (lockAOrderBook)
      {
        if (firstFill && hRest.Contains(marketSymbol))////firstFill=true  до начала коррекции данными WebSocket, hRest вначале содержит все символы hashSetWorkForArbitrage 
        {
          if (!DicFirstListOrderBook.TryGetValue(marketSymbol, out List<SocketOrderBook> lOrderBook))
          {
            lOrderBook = new List<SocketOrderBook>(200);
            DicFirstListOrderBook.TryAdd(marketSymbol, lOrderBook);
          }
          lOrderBook.Add(socketorderbook);
          if (dtStart == default) { dtStart = DateTime.Now; return; }
          else if ((DateTime.Now - dtStart).TotalSeconds <= 10) return;
          else
          {
            if (DicOrderbook.Count == 0)
            {              
              Parallel.ForEach(hashSetWorkForArbitrage, async (vvv) =>
              {
                var v = vvv;
                object objectOrderBookREST = await GetOrderBook(v);
                if (objectOrderBookREST is RootOrderBook rEST1)
                {
                  var rEST = rEST1.data;
                  if (!DicOrderbook.TryAdd(v, rEST))//ошибка! Откуда в DicOrderbook уже есть такой ключ?
                  { throw new Exception("!DicOrderbook.TryAdd(v, rEST)"); }
                }
                else
                {
                  //обработка                 
                }               
              });
              WriteLine("В DicOrderbook добавлены ордера для всех пар");
              return;
            }            
          }
        }       
      }
    }
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
09.06.2021, 18:47
Ответы с готовыми решениями:

Ошибка при заполнении коллекции Dictionary
Доброго времени суток пытаюсь занести в коллекцию значение получаемое функцией через делегат но он выходит из зоны видимости не пойму...

"Ключ отсутствует в словаре" при заполнении Dictionary из файла
здравствуйте. у меня такая проблема. создаю словарь из файла и подсчитываю кол-во каждого слова в файле. выдает ошибку на строку 32....

Ошибка при заполнении
Почему выбивает ошибку &quot;Индекс находился вне границ массива.&quot; ???? using System; using System.Collections.Generic; using...

8
 Аватар для Cupko
658 / 595 / 171
Регистрация: 17.07.2012
Сообщений: 1,682
Записей в блоге: 1
09.06.2021, 19:01
Цитата Сообщение от Fylhtq05 Посмотреть сообщение
но это же правило для исключения взаимоблокировок?
Это правило для того, чтобы ерунда всякая не происходила.
Ибо один и тот же поток может выполнять несколько асинхронных операций и lock вам ничего не даст.
1
109 / 52 / 16
Регистрация: 09.06.2021
Сообщений: 480
09.06.2021, 19:34  [ТС]
А если использовать не Task и async, а потоки, то можно под lock запускать несколько потоков и с кодом, который должен выполнится после их завершения?
0
 Аватар для Cupko
658 / 595 / 171
Регистрация: 17.07.2012
Сообщений: 1,682
Записей в блоге: 1
09.06.2021, 19:48
Fylhtq05, можно.
А еще можно использовать другие механизмы синхронизации, например Семафор, и не трогать потоки.
1
109 / 52 / 16
Регистрация: 09.06.2021
Сообщений: 480
09.06.2021, 19:55  [ТС]
А Mutex вместо lock можно использовать? Это пока не дописали код, позволяющий под lock использовать await или здесь что-то принципиальное, что позволяет потоки использовать, а задачи нет?
0
 Аватар для Cupko
658 / 595 / 171
Регистрация: 17.07.2012
Сообщений: 1,682
Записей в блоге: 1
09.06.2021, 20:03
Fylhtq05, Mutex - нет
Тут дело не в задачах и потоках, а в async/await механизме. Нет гарантии, что один и тот же поток не сможет завладеть локом дважды, как и гарантии того, что после await код выполнится в том потоке, который изначально завладел локом.

Добавлено через 3 минуты
А вообще, не проще ли избавиться от общего ресурса, того самого DicOrderbook, и не городить всей этой ерунды? В чем сакральный смысл этого словаря в поле, если он заполняется один лишь раз?
1
109 / 52 / 16
Регистрация: 09.06.2021
Сообщений: 480
10.06.2021, 15:07  [ТС]
Избавиться от DicOrderbook нельзя. Я показал только начальную часть кода без дальнейшей обработки, поэтому и кажется, что он не нужен. Смысл в следующем. Словарь хранит для каждого символа актуальные данные (набор действующих ордеров по каждому символу). Этот набор, OrderBook по каждому символу обновляется очень часто, несколько раз в секунду: какие-то ордера удаляются, какие-то частично исполняются, какие-то выставляются. Все данные этого набора, которых много для каждого символа можно получить делая запрос REST, т.е. объект HttpClient делает запрос, получает ответ и дальше после десериализации получается OrderBook (тот самый набор ордеров). Делать часто такие запросы означает сильную загрузку сервера. Поэтому сервер посылает по WebSocket изменение OrderBook, как только это изменение происходит. Эти изменения программа вносит в имеющийся OrderBook каждого символа, каждый раз при приходе по WebSocket этих изменений и дальше начинается основная работа с актуальным OrderBook, содержащегося в словаре для каждого символа.
Переписал код:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
List<Thread> lt = new(54);
              List<object> lo = new(54);
              foreach (string v in hashSetWorkForArbitrage)
              {
                object o;
                Thread t1 = new Thread(() =>
                {
                  o = GetOrderBook(v).Result; lo.Add(o);//запросы REST всех OrderBook для всех символов v
//Но почему-то делается не весь foreach, а только для первого символа, хотя весь код с подготовительной частью в lock
//Почему выполняется только одна итерация foreach?
                });
                lt.Add(t1);
              }
              foreach (var v in lt) v.Start();
              foreach (var v in lt) v.Join();
              foreach (var o in lo)
              {
                if (o is RootOrderBook rEST1)//Id = 8668, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"
                {
                  var rEST = rEST1.data;
                  if (!DicOrderbook.TryAdd(rEST.namePair, rEST)) { throw new Exception("!DicOrderbook.TryAdd(v, rEST)"); }
                }
                else { }//точка остановки
              }
Т.е. задача начать получать данные по WebSocket, накапливая их в словаре DicFirstListOrderBookчерез 10 секунд выполнить запрос по всем символам, далее синхронизация изменений с потоком WebSocket (каждый возврат OpderBook и каждое данное по WebSocket имеет sequence, чтобы знать с какого моменты начать производить изменения OrderBook.
Я написал не асинхронную программу: запросы Rest делаются в цикле не асинхронно. Т.к. это долго (надо ждать когда будет получен ответ от предыдущего запроса) переполняется буфер (то ли у меня, то ли у провайдера) данными по WebSocket, если символов, которым соответствует каждый OrderBook больше 30. И вот сделать одновременный запрос по HttpClient по более 50 символам, т.е. более 50 запросов одновременно, на это время блокируя данные WebSocket ( но так, чтобы блокируемые данные получить после выполнения запросов, т.е. чтобы блокируемые данные не исчезли), пока не могу. Не получилось с Async и не получается с Thread.
0
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
12.06.2021, 00:00
Цитата Сообщение от Fylhtq05 Посмотреть сообщение
программа должна начать получать данные по WebSocket, накапливая их в , через 10 секунд сделать запросы Rest
Почитайте про Поток данных, не уверен, но кажись тут вырисовывается буфер с активацией по таймеру.
1
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,109
Записей в блоге: 2
12.06.2021, 12:29
Цитата Сообщение от Fylhtq05 Посмотреть сообщение
ошибка! Откуда в DicOrderbook уже есть такой ключ?
Такая параллельна обработка полная бессмыслица.
Ключи добавляются в DicOrderbook по одному.
Вы хоть как это оформите, закодируйте - вы ничего этим не измените.
Всё что вы экономите это время запроса = await GetOrderBook(v);.
Ну, так и получите все данные асинхронно но в словарь их добавьте синхронно.

Примерный код:
C#
23
24
25
26
27
28
29
30
31
32
33
34
    Task<object>[] tasks = hashSetWorkForArbitrage
            .Select(vvv => Task<object>.Run(GetOrderBook(vvv))
            .ToArray();
 
    await Task.Run(() => Task.Wait(tasks));
 
    foreach(var task in tasks)
    {
        object objectOrderBookREST = task.Result;
 
                  //обработка                 
    }
И то для такого кода нужна гарантия, что может единовременно выполняться несколько запросов GetOrderBook(...).
Если такой гарантии нет, то вполне возможны исключения, или когда в ответ на один запрос будет приходить ответ от предыдущего или следующего.

Добавлено через 1 минуту
Судя по описанию вашей проблемы у вас происходит именно путаница в ответах при асинхронной отправке единовременно множества запросов.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
12.06.2021, 12:29
Помогаю со студенческими работами здесь

Ошибка при заполнении массива
Здравствуйте. Есть класс, в котором объявлены 2 поля и 2-мерный массив. Создал метод, который задает кол-во строк и столбцов, а затем...

Ошибка при заполнении DataGridView
Всем привет! Вроде все просто заполнить базу в форме 2 тексбухстами из 3 формы! Ошибка! В чем проблема?

Ошибка при заполнении массива
Нужно заполнить массив в четных индексах 1-цей , а в нечетных значением i / 5; using System; using System.Collections.Generic; ...

Ошибка при заполнении массива
Есть код: Random r = new Random(); int k = r.Next(0, 10000); int kk = { k }; for (int i = 0; i &lt; k; i++) { kk = i; //Вот...

Ошибка при выводе Dictionary в DataGridView
При попытке вывести Dictionary в DataGridView выводит ошибку - Индекс за пределами диапазона. Индекс должен быть положительным числом, а...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru