Nano Hash - криптовалюты, майнинг, программирование

Как предотвратить одновременное выполнение нескольких http-запросов

У меня есть массив объектов. Для каждого объекта мне нужно инициировать асинхронный запрос (http-вызов). Но я хочу, чтобы одновременно выполнялось определенное количество запросов. Кроме того, было бы неплохо (но не обязательно), если бы я мог иметь одну единственную точку синхронизации после завершения всех запросов для выполнения некоторого кода.

Я пробовал предложения от:

Ограничение количества запросов за раз с помощью RxJS< /а>

Как ограничить параллелизм flatMap?

Выполнить асинхронный запрос параллельно, но получить результат чтобы использовать rxjs

и многое другое... Я даже пробовал делать свои собственные операторы.

Либо ответы на этих страницах слишком устарели для работы с моим кодом, либо я не могу понять, как собрать все вместе, чтобы все типы подходили друг другу.

Это то, что у меня есть до сих пор:

for (const obj of objects) {
  this.myService.updateObject(obj).subscribe(value => {
    this.anotherService.set(obj);
  });
}

РЕДАКТИРОВАТЬ 1: Хорошо, я думаю, у нас все получилось! С ответами Julius и pschild (оба работают одинаково) мне удалось ограничить количество запросов. Но теперь он будет запускать только первую партию из 4 и никогда не запускает остальные. Итак, теперь у меня есть:

const concurrentRequests = 4;
from(objects)
  .pipe(
    mergeMap(obj => this.myService.updateObject(obj), concurrentRequests),
    tap(result => this.anotherService.set(result))
  ).subscribe();

Я что-то не так делаю с subscribe()?

Кстати: параметр mergeMap с параметром resultSelector устарел, поэтому я использовал mergeMap без него. Кроме того, obj из mergeMap не отображается в tap, поэтому мне пришлось использовать параметр tap.

ИЗМЕНИТЬ 2:

Убедитесь, что ваши наблюдатели завершены! (Это стоило мне целого дня)


  • Да, вы правы с устареванием :-) Я соответственно обновил свой ответ. Не могли бы вы взглянуть на мой пример на Stackblitz? Я не могу воспроизвести ошибки, которые вы получили... может быть, вы могли бы также создать пример, показывающий ошибки? 19.05.2019
  • Я не могу воспроизвести проблему в Stackblitz. Я не думаю, что это имеет какое-то отношение к angular/electron/nodejs... по крайней мере, я надеюсь. В любом случае, вот Stackblitz, который больше похож на мой код: https://stackblitz.com/edit/rxjs-dawwsl?file=index.ts Клянусь, я проверил символ кода на символ, но все же.. Единственное, что я могу сказать, это то, что мой код не попадает в метод финализации. Но все первые 4 запроса проходят через трубу хорошо. 19.05.2019
  • Да и на консоли ошибок нет. Как узнать, где и почему он застрял? Я пробовал с оператором catchError - не повезло. 19.05.2019
  • Я думаю, что схожу с ума. Я скопировал код stackblitz в свое приложение, и он работает... поэтому я могу исключить свой электронный/угловой стек и т. д. Я создал еще один stackblitz, который еще ближе к моему коду: https://stackblitz.com/edit/angular-7-master-yf1cik И я попробовал функцию ошибки внутри метода subscribe... ничего 19.05.2019
  • Итак, вы говорите, что последний Stackblitz, который вы предоставили, работает (это работает для меня), но в вашем реальном коде это не так? Я думаю, что должно быть другое объяснение этому поведению, и поэтому я предполагаю, что просто нет ошибки времени выполнения, которую можно было бы отловить с помощью catchError или функции error в subscribe. Используете ли вы те же версии rxjs? Что произойдет, если вы поиграетесь с concurrentRequests, установив его на 1 или 100? Трудно сказать, но между двумя вашими базами кода должна быть какая-то разница. 19.05.2019
  • Я понял это! Проблема заключалась в том, что мой наблюдатель, который я создал в сервисном методе, так и не завершился. Ваш наблюдатель of(..), конечно, завершен, поэтому он работал. Итак, я добавил observer.complete() и вуаля! Спасибо за вашу помощь! 19.05.2019
  • Хороший! Рад, что смог помочь! 19.05.2019

Ответы:


1

Вы можете использовать третий параметр mergeMap, чтобы ограничить количество одновременных внутренних подписок. . Используйте finalize, чтобы выполнить что-то после завершения всех запросов:

const concurrentRequests = 5;
from(objects)
    .pipe(
        mergeMap(obj => this.myService.updateObject(obj), concurrentRequests),
        tap(res => this.anotherService.set(res))),
        finalize(() => console.log('Sequence complete'))
    );

См. пример на Stackblitz.

18.05.2019

2
from(objects).pipe(
  bufferCount(10),
  concatMap(objs => forkJoin(objs.map(obj => 
    this.myService.updateObject(obj).pipe(
      tap(value => this.anotherService.set(obj))
  )))),
  finalize(() => console.log('all requests are done'))
)

Код не тестировался, но идея понятна. Дайте мне знать, если потребуется какая-либо ошибка или объяснение

18.05.2019
  • Ваш ответ, вероятно, тоже сработал бы, но мне немного больше понравился подход pschild. 19.05.2019
  • Полностью согласен - не знал, что mergeMap имеет concurrent опору 19.05.2019

  • 3

    У меня была такая же проблема однажды. Когда я попытался загрузить несколько изображений с сервера. Пришлось отправлять http запросы один за другим. Я достиг желаемого результата, используя ожидаемое обещание. Вот пример кода:

    async ngOnInit() {
        for (const number of this.numbers) {
          await new Promise(resolve => {
            this.http.get(`https://jsonplaceholder.typicode.com/todos/${number}`).subscribe(
              data => {
                this.responses.push(data);
                console.log(data);
                resolve();
              }
            );
          });
        }
      }
    

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

    Вот stackblitz . Откройте консоль, чтобы увидеть ее в действии. :)

    18.05.2019
  • использование Promises больше не является хорошей практикой. Даже если у вас есть обещание, его следует преобразовать в Observable 18.05.2019
  • Спасибо, но я хотел использовать операторы, чтобы лучше понять их. 18.05.2019
  • Новые материалы

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

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

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..