высокая производительность udp сервер. блокирование или неблокирование? c

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

немного фона на моем собственном проблемном наборе, так, чтобы ответы могли потенциально быть применены конкретно, а также к общему характеру вопроса. у меня есть udp сервер, что я пишу, что это будет иметь 40 соединений на локальной LAN, посредством чего будет втекать постоянный поток данных. скорости передачи данных будут вокруг 250MB/s в среднем с пиками к 500+Mb/s с в среднем размером датаграммы на уровне приблизительно 1 400 байтов. обработка датаграмм легка, но из-за большого объема msgs эффективности и производительности высокий приоритет для предотвращения отброшенных пакетов.

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

~edit ~

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

~edit2 ~

во-первых, требуемый для высказывания заправляют Вас для ответов до сих пор. несколько из Вас упомянули, что single-thread/socket модель с этим, много сокетов могут быть плохой идеей и я признаю, что был предварительным с решением сам. однако, в одной из ссылок в reponse nikolai, автор обсуждает single-thread/socket модель и ссылки на очень интересную статью, что я думал, что свяжусь со здесь, поскольку это рассеивает много мифов, которые я держал о потоках по сравнению с основанными на событии моделями: почему события являются плохой идеей

8
задан ROMANIA_engineer 21 August 2019 в 13:54
поделиться

4 ответа

Не ответ, просто несколько ссылок, если их еще нет в закладках:

Проблема C10K Дэна Кегеля,
Высокопроизводительная серверная архитектура Джеффа Дарси,
Расширенные API опросов: epoll (4) , kqueue (2) .

Редактировать:

Как бы глупо это ни звучало, но я совершенно упустил из виду, что вы работаете с UDP, поэтому ...

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

5
ответ дан 5 December 2019 в 18:59
поделиться

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

  • Если единственное, что ваш сетевой поток ввода-вывода когда-либо собирается делать, это прослушивать входящие пакеты UDP на одном сокете, тогда блокировка ввода-вывода, вероятно, будет работать нормально и ее будет легче программировать.

  • Если ваш сетевой поток ввода-вывода должен обрабатывать более одного сокета, то блокирование ввода-вывода становится проблематичным, потому что, если он блокируется на сокете A, он не будет разбужен для обработки данных, поступающих на сокет B, или наоборот. В этом случае предпочтительным становится неблокирующий ввод-вывод, поскольку вы можете выполнить блокировку в select () или poll (), которые будут возвращаться всякий раз, когда данные доступны на любом из наблюдаемых сокетов.

Обратите внимание, что даже в неблокирующем случае вы не захотите зацикливаться между пакетами, поскольку запись циклов ЦП в потоке A означает, что они не будут доступны потоку B, что снизит производительность. Поэтому, если вы не блокируете в recv (), не забудьте вместо этого заблокировать в select () или poll ().

2
ответ дан 5 December 2019 в 18:59
поделиться

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

Что касается блокирования и неблокирования, помните, что блокирование может быть относительно дорогостоящим... хотя, на мой взгляд, с ним проще работать. Асинхронные триггеры и т.д., вероятно, в целом быстрее, чем необходимость блокировать/пробуждать поток.

0
ответ дан 5 December 2019 в 18:59
поделиться
  • при использовании блокирующего ввода-вывода, в какой-то момент в вашей программе вы должны иметь опрос или select, ожидающий данных на любом из ваших файловых хэндлов (в вашем случае сокетов). Потому что если вы читаете на любом из ваших fh, не убедившись, что данные на нем готовы, он заблокируется, и программа перестанет управлять другими сокетами. Чтобы избежать этого и сохранить простоту программы, программы, использующие блокирующий ввод-вывод, часто пишутся с одним потоком для каждого сокета/fh, что позволяет избежать необходимости в poll или select.

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

Я считаю, что наиболее эффективным подходом является использование poll или select для управления несколькими IO одновременно (это может быть подмножество всех файловых обращений, разделенных между потоками, если вы хотите). Это более эффективно, чем неблокирующий IO без poll или select, потому что этот метод в основном пытается читать на каждом сокете большую часть времени бесполезно, и это имеет свою цену. Худшим методом из этих трех является использование блокирующего ввода-вывода с одним fh для каждого потока, из-за высокой стоимости управления потоками по сравнению с чтением, возвращающим WOULDBLOCK или poll.

При этом у неблокирующего ввода-вывода есть еще одно преимущество: Ваша программа может иметь вычисления, которые нужно делать помимо ввода-вывода, и когда блокируется ожидание ввода-вывода, вы не можете этого сделать. Это может привести к использованию poll/select с неблокирующим IO или использованию его с небольшим таймаутом, или даже использованию небольшого специализированного потока, предназначенного для IO, и других потоков для более интенсивных в вычислительном отношении частей программы.

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

Вы также можете рассмотреть возможность использования асинхронного ввода-вывода. Это очень эффективно, ваша программа становится "управляемой событиями". Это вполне обычно для систем windows, я не смотрел текущее состояние развития асинхронного ввода-вывода для Linux. Последний раз, когда я проверял, некоторые люди работали над добавлением асинхронного ввода-вывода в API ядра, но я не знаю, стабильно ли это или достигло основных ядер.

2
ответ дан 5 December 2019 в 18:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: