Книга: UNIX: разработка сетевых приложений
30.13. Резюме
30.13. Резюме
В этой главе мы рассмотрели 9 различных версий сервера и их работу с одним и тем же веб-клиентом, чтобы сравнить значения времени центрального процессора, затраченного на управление процессом.
0. Последовательный сервер (точка отсчета — управление процессом отсутствует).
1. Параллельный сервер, по одному вызову функции fork
для каждого клиента.
2. Предварительное порождение дочерних процессов, каждый из которых вызывает функцию accept
.
3. Предварительное порождение дочерних процессов с блокировкой файла для защиты функции accept
.
4. Предварительное порождение дочерних процессов с блокировкой взаимного исключения дочерними процессами для защиты функции accept
.
5. Предварительное порождение дочерних процессов с передачей дескриптора от родительского процесса дочернему.
6. Параллельный сервер, поочередное создание потоков по мере поступления клиентских запросов.
7. Предварительное порождение потоков с блокировкой взаимного исключения потоками для защиты функции accept
.
8. Предварительное порождение потоков, основной поток вызывает функцию accept
.
Резюмируя материал этой главы, можно сделать несколько комментариев.
? Если сервер не слишком загружен, хорошо работает традиционная модель параллельного сервера, в которой при поступлении очередного клиентского запроса вызывается функция fork
для создания нового дочернего процесса. Этот вариант допускает комбинирование с демоном inetd
, принимающим все клиентские запросы. Остальные версии применимы в случае загруженных серверов, таких как веб-серверы.
? Создание пула дочерних процессов или потоков сокращает временные затраты центрального процессора по сравнению с традиционной моделью (один вызов функции fork
для каждого запроса) в 10 и более раз. При этом не слишком усложняется код, но становится необходимо (как говорилось при обсуждении примеров) отслеживать количество свободных дочерних процессов и корректировать его по мере необходимости, так как количество клиентских запросов, которые требуется обслужить, динамически изменяется.
? Некоторые реализации допускают блокирование нескольких потоков или дочерних процессов в вызове функции accept
, в то время как другие реализации требуют использования блокировки того или иного типа для защиты accept
. Можно использовать для этого либо блокировку файла, либо блокировку взаимного исключения Pthreads.
? Как правило, версия, в которой каждый поток или дочерний процесс вызывает функцию accept
, проще и быстрее, чем версия, где вызов функции accept
осуществляется только основным потоком (или родительским процессом), впоследствии передающим дескриптор присоединенного сокета другому потоку или дочернему процессу.
? Блокировка всех дочерних процессов или программных потоков в вызове функции accept
предпочтительнее, чем блокировка в вызове функции select
, что объясняется возможностью появления коллизий при вызове функции select
.
? Использование потоков, как правило, дает больший выигрыш во времени, чем использование процессов. Но выбор между версиями 1 и 6 (один дочерний процесс на каждый запрос и один поток на каждый запрос) зависит от свойств операционной системы и от того, какие еще программы задействованы в обслуживании клиентских запросов. Например, если сервер, принимающий клиентское соединение, вызывает функции fork
и exec
, то может оказаться быстрее породить с помощью функции fork
процесс с одним потоком, чем процесс с несколькими потоками.
- 30.1. Введение
- 30.2. Альтернативы для клиента TCP
- 30.3. Тестовый клиент TCP
- 30.4. Последовательный сервер TCP
- 30.5. Параллельный сервер TCP: один дочерний процесс для каждого клиента
- 30.6. Сервер TCP с предварительным порождением процессов без блокировки для вызова accept
- 30.7. Сервер TCP с предварительным порождением процессов и защитой вызова accept блокировкой файла
- 30.8. Сервер TCP с предварительным порождением процессов и защитой вызова accept при помощи взаимного исключения
- 30.9. Сервер TCP с предварительным порождением процессов: передача дескриптора
- 30.10. Параллельный сервер TCP: один поток для каждого клиента
- 30.11. Сервер TCP с предварительным порождением потоков, каждый из которых вызывает accept
- 30.12. Сервер с предварительным порождением потоков: основной поток вызывает функцию accept
- 30.13. Резюме
- Упражнения