Проблема с потоками в ASP.NET Core

У меня есть проект веб-API ASP.NET Core. У этого есть один контроллер с методом GetLocations.

GetLocations подключается к 5 другим веб-службам в Интернете. Собирает информацию и возвращает коллекцию через json. В этом методе я кэширую данные каждые 5 минут, используя кеширование в памяти.

Если срок действия кеша истекает, он пытается подключиться ко всем 5 службам, получить информацию и так далее.

Моя проблема:

У меня много пользователей, которые постоянно запрашивают эти данные, 50 запросов в секунду к этому API.

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

Верно ли мое предположение? Если да, то как я могу это исправить? Нужно ли будет выполнять каждый вызов веб-служб асинхронно? Поможет ли это в этом сценарии? Я не уверен на 100%, потому что запросы - это то, что запускает вызов метода.

"Верно ли мое предположение?" --- учитывая, что вы буквально ничего не предоставили, это может быть с равной вероятностью: Да / Нет / Может быть.

zerkms 14.11.2018 02:00

Было бы здорово, если бы вы могли предоставить минимальный воспроизводимый пример.

mjwills 14.11.2018 02:03

При обновлении я бы создал временный кеш, который, когда он будет скопирован в действующую систему, будет работать медленно в течение очень короткого времени.

Poul Bak 14.11.2018 03:07
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
634
2

Ответы 2

Вы обязательно должны выполнять вызовы внешних служб с использованием Async / Await.

Это просто данность - лучше всего всегда использовать асинхронный режим для тяжелых операций ввода-вывода (таких как вызов сторонней службы).

Теперь вы также должны создать класс, который управляет этими вызовами. Вы можете добавить его как Singleton в свой IoCConfig. В этом классе убедитесь, что вы «блокируете», чтобы избежать проблемы, которую вы только что описали, и не вызывайте базовые службы несколько раз во время создания кеша.

Проверить здесь: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement

«всегда использовать асинхронный режим для тяжелых операций ввода-вывода» --- асинхронный режим не является бесплатным, у вас могут быть случаи, когда блокирование ввода-вывода предпочтительнее из-за требований к производительности. Я согласен с тем, что в целом async может быть выбором по умолчанию, я считаю, что «всегда» здесь сильное слово.

zerkms 14.11.2018 02:05

Вы столкнулись с этой проблемой по следующей причине.

  1. Вы используете кеш, и его срок действия истечет через определенное время.
  2. По истечении срока действия кэша вы вызываете метод внешней веб-службы для сбора данных. Теперь в этот момент может случиться так, что другой запрос в очереди будет выбран для выполнения.
  3. После того, как этот другой запрос выбран для выполнения, он также завершает проверку кеша, и теперь данные в кеше, затем выполняют внешнюю службу и так далее для другого запроса.

Решение этого.

  1. Кэш первой проверки содержит данные или нет.
  2. Если не создать блокировку, следующий раздел будет выполняться только одним потоком.
  3. Теперь в этом разделе блокировки снова проверьте кеш, и если кеш содержит данные, просто вернитесь, но он не содержит, затем вызовите внешнюю службу.
  4. В этот момент, если для выполнения выбран другой поток, он должен дождаться, пока исполняемый раздел завершит свою работу.
  5. Как только этот раздел будет завершен, он сохранит данные в кеше, и поэтому после того, как появится какой-либо очередной или новый запрос, он выберет данные из кеша.

Примечание: должно получиться что-то вроде этого.

    public List<string> GetData()
    {
     if (Cache[key] == null)
    {
       lock(obj) // obj should be static
       {
            if (Cache[key] == null)
            {
                // Load data from service
                Cache[key] == data;
            }
        }
     }
     return (List<string>)Cache[Key]; 
     }

Другие вопросы по теме