Оптимальное время сна в модели нескольких производителей / одного потребителя

StackOverflow https://stackoverflow.com/questions/1400605

  •  05-07-2019
  •  | 
  •  

Вопрос

Я пишу приложение, в котором используется модель с несколькими производителями, одна потребительская модель (несколько потоков отправляют сообщения в один поток записи файлов).

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

В цикле потока потребителя он спит в течение определенного периода времени после обработки всех потоков производителя. Одна вещь, которую я сразу заметил, заключалась в том, что среднее время, в течение которого производитель записывает что-либо в очередь и возвращает его, резко увеличилось (в 5 раз), когда я перешел с 1 потока производителя на 2. По мере добавления новых потоков это среднее время уменьшается до тех пор, пока оно не достигнет нижнего уровня. вне - нет большой разницы между временем, проведенным с 10 производителями против 15 производителей. Вероятно, это связано с тем, что чем больше производителей обрабатывают, тем меньше конкуренции за мьютекс потока производителей.

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

Кто-нибудь еще сталкивался с этим, и если да, каково было ваше решение? Я попытался масштабировать время ожидания с количеством потоков, но это выглядит несколько специфично для машины и довольно методом проб и ошибок.

Это было полезно?

Решение

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

В любом случае, вы решаете более фундаментальную проблему. Спать и опрашивать легко, а иногда это единственный доступный подход, но он имеет много недостатков и не является & Quot; right & Quot; путь.

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

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

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

Вместо того, чтобы спать, я бы порекомендовал вашему потребителю заблокировать состояние, указанное производителями. В posix-совместимой системе вы можете заставить ее работать с pthread_cond. Создайте массив pthread_cond_t, по одному для каждого производителя, а затем создайте дополнительный, который будет разделен между ними. Производители сначала сигнализируют свою индивидуальную переменную условия, а затем - общую. Потребитель ожидает выполнения условия общего доступа и затем перебирает элементы массива, выполняя pthread_cond_timed_wait() для каждого элемента массива (используйте pthread_get_expiration_np(), чтобы получить абсолютное время для & Quot; now & Quot; ). Если ожидание возвращает 0, то этот производитель записал данные. Потребитель должен повторно инициализировать переменные условия перед повторным ожиданием.

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

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

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

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

Можете показать какой-нибудь код?

edit: может быть, вы берете блокировку и меняете очереди, даже когда нет работы?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top