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

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

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

Я думал об очереди на хост, но тогда сложно поддерживать первоначальный порядок.

Я думаю иметь одну очередь, атрибут для хоста для каждого элемента и подпрограмму, чтобы пройти через очередь, пока она не найдет первую, которая имеет доступные сокеты, а затем удалить ее из очереди путем сплайсинга. Это сохраняет первоначальный порядок, но кажется, что он может быть неэффективным.

Поэтому я думаю объединить подходы с чем-то вроде этого (поддерживая общую очередь с помощью атрибута «order»):

 const queues = [ { host: 'www.example.org', queue: [ { order: 1 }, { order: 3 } ] }, { host: 'www.example.com', queue: [ { order: 2 }, { order: 4 }, { order: 5 } ] } ]; 

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

Я делал что-то подобное в прошлом для веб-сканера.

У меня был класс Host который содержал информацию о хосте: имя, максимальное количество одновременных запросов, текущее количество активных запросов, копию его файла robots.txt, статистику его истории (количество запросов, которые я сделал к нему, среднее скорость отклика, частота ошибок и т. д.) и другая информация, относящаяся к хосту.

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

Когда я удалил запрос из очереди, первым делом я проверил Host чтобы увидеть, есть ли доступные сокеты. Если нет, я бы просто поставил запрос в очередь со значением времени сейчас среднее время запроса хоста.

Это сработало, хотя URL-адреса некоторых очень загруженных хостов часто перерабатывались.

Я экспериментировал с приоритетной очередью хостов. У каждого хоста была очередь или URL. Также был список тайм-аутов: словарь хостов, которые в настоящее время находились в состоянии «тайм-аут» по разным причинам, но главным образом потому, что не было доступных сокетов, или его очередь URL была пустой. Вот как это работает:

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

Такой подход выглядел многообещающим. Мы тестировали его, когда проект был отменен по другим причинам.