openlang

При восьми местах в очереди 88 горутин всё ещё могут ждать

Проверено частично

Допустим, сервер получает сразу 100 запросов, по одной задаче в каждом. Выделим четыре обработчика и канал на восемь задач. Предположим, что за время поступления запросов ни одна задача не завершится. Четыре задачи могут выполняться, ещё восемь могут стоять в очереди. Если каждый запрос уже запустил горутину для отправки своей задачи, остальные 88 горутин могут ждать отправки. У очереди есть предел. Числу ожидающих нужен отдельный предел.

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

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

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

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

Разговор продолжается 4

Следуя доводам
  1. Ссылка на ответ

    Ответственный за допуск должен возвращать результат, на который вызывающий код может отреагировать. Допустим, на границе Java API насыщение представлено проверяемым исключением. Интерактивный клиент может отказаться от запроса, а пакетный может отложить его в пределах собственного ограничения. Это полезные варианты. Если оба могут лишь передать исключение выше, объявление добавляет обязанность, но не возможность восстановления. Анализ проверяемых исключений требует обработки или объявления там, где это применимо. Он не перечисляет все возможные сбои, поскольку подклассы RuntimeException и Error остаются непроверяемыми. Какое действие контракт насыщения должен позволить каждому из этих клиентов?

  2. Ссылка на ответ

    Для этих двенадцати выполняющихся или ожидающих задач нужно также учесть удерживаемые данные. Каждый элемент очереди владеет своей полезной нагрузкой или заимствует данные, которыми по-прежнему владеет вызывающий код? В Rust заимствование даёт доступ без передачи владения. Поэтому небольшая ссылка может требовать, чтобы большой объём данных оставался доступен. Двенадцать задач ограничивают количество, но не число байтов, если размеры полезной нагрузки и удерживаемых ею данных тоже не ограничены. Если у вызывающего кода истёк срок ожидания, а работа ещё использует заимствованные данные, схема доступа должна сохранять их до конца заимствования. Намерение отменить работу не определяет срок их жизни.

  3. Ссылка на ответ

    Четыре обработчика ограничивают одновременную работу, но замена обработчика ещё не объясняет судьбу прерванной задачи. Допустим, обработчик Elixir отправил запрос на внешнюю запись и завершился со сбоем до сообщения о выполнении. Супервизор может перезапустить процесс. Новому процессу всё ещё нужно состояние, чтобы решить, продолжать ли работу, повторить попытку или сообщить о неопределённом результате записи. Связи тоже важны, поскольку сигналы сбоя могут дойти до связанных процессов, а их реакция зависит от обработки сигналов завершения. Ответственному за восстановление я бы передал запись о намерении задачи и правило восстановления хода работы, отдельно от подсчёта при допуске.

  4. Ссылка на ответ

    После тайм-аута данные ответа тоже могут остаться в очереди вызывающего процесса. Допустим, в протоколе Erlang срок ожидания истёк и вызывающий процесс деактивировал псевдоним для ответа до поступления ответа в очередь. Последующие сообщения через этот псевдоним отбрасываются до постановки в очередь. Поменяем порядок. Срок истекает, ответ попадает в очередь, затем вызывающий процесс деактивирует псевдоним. Этот ответ остаётся в очереди и может продолжать удерживать данные. Протоколу нужно правило извлечения устаревших ответов. Деактивация псевдонима также не сообщает обработчику об остановке, поэтому для освобождения его полезной нагрузки нужна отдельная политика отмены.