Составители:
Рубрика:
из занятых потоков. Такой подход обеспечивает, с одной стороны, малые
затраты на управление потоками, с другой – достаточно высокую загрузку
процессоров и хорошую масштабируемость приложения.
Обычно имеет смысл ограничивать общее число рабочих потоков ли-
бо числом доступных процессоров, либо кратным этому числом. Если по-
токи занимаются исключительно вычислительной работой, то их число не
должно превышать число процессоров. Если потоки, сверх того, проводят
некоторое время в состоянии ожидания (например, при выполнении опе-
раций ввода-вывода), то число потоков следует увеличить – решение сле-
дует принимать, исходя из доли времени, которое поток проводит в состо-
янии простоя, и из полного времени обработки запроса.
Достаточно типичная рекомендация: ограничивать число потоков
удвоенным числом процессоров. В случае вычислительных потоков на-
кладные потери будут достаточно малы; в случае потоков, занятых вво-
дом-выводом, утилизация процессоров будет близка к полной. Предпола-
гается, что потоки, не занятые вводом-выводом и при этом проводящие
много времени в состоянии ожидания, встречаются весьма редко.
Реализация пула потоков является, на самом деле, нетривиальной за-
дачей – необходимо поддерживать очередь запросов и учитывать состоя-
ния потоков из пула (поток простаивает; поток выполняется; поток вы-
полняется, но находится в состоянии ожидания). Также следует учитывать
возможность выгрузки части данных в файл подкачки (например, выгруз-
ка стека давно не используемого потока) – иногда быстрее подождать за-
вершения работающего потока, чем активировать простаивающий. Для
учета всех этих соображений необходимо реализовать поддержку пулов
потоков ядром операционной системы, так как на уровне приложения
некоторые нужные сведения просто недоступны.
В Windows такая поддержка реализована в виде порта завершения вво-
да-вывода. Этот объект ядра берет на себя функциональность, необходи-
мую для организации очереди запросов (используя для этого очередь APC)
и списков рабочих потоков, обеспечивая оптимальное управление пулом.
С точки зрения разработчика приложения необходимо:
• создать порт завершения ввода-вывода;
• создать пул потоков, ожидающий поступления запросов от это-
го порта;
• обеспечить передачу запросов порту.
Порт завершения создается с помощью функции
HANDLE CreateIoCompletionPort(
HANDLE FileHandle, HANDLE ExistingCompletionPort,
ULONG_PTR CompletionKey, DWORD NumberOfConcurrentThreads
);
Разработка параллельных приложений для ОС Windows
219
Глава 7.
Разработка параллельных приложений
для ОС Windows
7.1. Применение потоков и волокон
При разработке параллельных приложений недостаточно создать
несколько параллельных ветвей кода – необходимо обеспечить их согласо-
ванное выполнение и своевременный обмен данными. При этом возникает
необходимость использования как общих для разных потоков и процессов
данных, так и создания собственных локальных данных, недоступных дру-
гим параллельным ветвям кода, может потребоваться синхронизация и даже
учет особенностей аппаратуры, на которой данный код будет исполняться.
7.1.1. Пулы потоков, порт завершения ввода-вывода
Одна из типовых задач – разработка серверов, обслуживающих асин-
хронно поступающие запросы. Реализация однопоточного сервера для та-
кой задачи нецелесообразна, во-первых, потому что запросы могут прихо-
дить в то время, пока сервер занят выполнением предыдущего, а, во-вто-
рых, потому что такой сервер не сможет эффективно задействовать много-
процессорную систему. Можно, конечно, запускать несколько экземпля-
ров однопоточного сервера – но в этом случае потребуется разработка спе-
циального диспетчера, поддерживающего очередь запросов и их распреде-
ление по списку доступных экземпляров сервера. Альтернативным реше-
нием является разработка многопоточного сервера, создающего по специ-
альному рабочему потоку для обработки каждого запроса. Этот вариант
также имеет свои недостатки: создание и удаление потоков требует затрат
времени, которые будут иметь место в обработке каждого запроса; сверх
того, создание большого числа одновременно выполняющихся потоков
приведет к общему снижению производительности (и значительному уве-
личению времени обработки каждого конкретного запроса).
Эти соображения приводят к решению, получившему название пула
потоков (thread pool). Для реализации пула потоков необходимо создание
некоторого количества потоков, занятых обслуживанием запросов, и дис-
петчера с очередью запросов. При наличии необработанных запросов дис-
петчер находит свободный поток и передает запрос этому потоку; если
свободных потоков нет, то диспетчер ожидает освобождения какого-либо
218
CIL и системное программирование в Microsoft .NET
218 CIL и системное программирование в Microsoft .NET Разработка параллельных приложений для ОС Windows 219 из занятых потоков. Такой подход обеспечивает, с одной стороны, малые Глава 7. затраты на управление потоками, с другой – достаточно высокую загрузку процессоров и хорошую масштабируемость приложения. Разработка параллельных приложений Обычно имеет смысл ограничивать общее число рабочих потоков ли- бо числом доступных процессоров, либо кратным этому числом. Если по- для ОС Windows токи занимаются исключительно вычислительной работой, то их число не должно превышать число процессоров. Если потоки, сверх того, проводят некоторое время в состоянии ожидания (например, при выполнении опе- раций ввода-вывода), то число потоков следует увеличить – решение сле- 7.1. Применение потоков и волокон дует принимать, исходя из доли времени, которое поток проводит в состо- янии простоя, и из полного времени обработки запроса. При разработке параллельных приложений недостаточно создать Достаточно типичная рекомендация: ограничивать число потоков несколько параллельных ветвей кода – необходимо обеспечить их согласо- удвоенным числом процессоров. В случае вычислительных потоков на- ванное выполнение и своевременный обмен данными. При этом возникает кладные потери будут достаточно малы; в случае потоков, занятых вво- необходимость использования как общих для разных потоков и процессов дом-выводом, утилизация процессоров будет близка к полной. Предпола- данных, так и создания собственных локальных данных, недоступных дру- гается, что потоки, не занятые вводом-выводом и при этом проводящие гим параллельным ветвям кода, может потребоваться синхронизация и даже много времени в состоянии ожидания, встречаются весьма редко. учет особенностей аппаратуры, на которой данный код будет исполняться. Реализация пула потоков является, на самом деле, нетривиальной за- дачей – необходимо поддерживать очередь запросов и учитывать состоя- 7.1.1. Пулы потоков, порт завершения ввода-вывода ния потоков из пула (поток простаивает; поток выполняется; поток вы- Одна из типовых задач – разработка серверов, обслуживающих асин- полняется, но находится в состоянии ожидания). Также следует учитывать хронно поступающие запросы. Реализация однопоточного сервера для та- возможность выгрузки части данных в файл подкачки (например, выгруз- кой задачи нецелесообразна, во-первых, потому что запросы могут прихо- ка стека давно не используемого потока) – иногда быстрее подождать за- дить в то время, пока сервер занят выполнением предыдущего, а, во-вто- вершения работающего потока, чем активировать простаивающий. Для рых, потому что такой сервер не сможет эффективно задействовать много- учета всех этих соображений необходимо реализовать поддержку пулов процессорную систему. Можно, конечно, запускать несколько экземпля- потоков ядром операционной системы, так как на уровне приложения ров однопоточного сервера – но в этом случае потребуется разработка спе- некоторые нужные сведения просто недоступны. циального диспетчера, поддерживающего очередь запросов и их распреде- В Windows такая поддержка реализована в виде порта завершения вво- ление по списку доступных экземпляров сервера. Альтернативным реше- да-вывода. Этот объект ядра берет на себя функциональность, необходи- нием является разработка многопоточного сервера, создающего по специ- мую для организации очереди запросов (используя для этого очередь APC) альному рабочему потоку для обработки каждого запроса. Этот вариант и списков рабочих потоков, обеспечивая оптимальное управление пулом. также имеет свои недостатки: создание и удаление потоков требует затрат С точки зрения разработчика приложения необходимо: времени, которые будут иметь место в обработке каждого запроса; сверх • создать порт завершения ввода-вывода; того, создание большого числа одновременно выполняющихся потоков • создать пул потоков, ожидающий поступления запросов от это- приведет к общему снижению производительности (и значительному уве- го порта; личению времени обработки каждого конкретного запроса). • обеспечить передачу запросов порту. Эти соображения приводят к решению, получившему название пула Порт завершения создается с помощью функции потоков (thread pool). Для реализации пула потоков необходимо создание некоторого количества потоков, занятых обслуживанием запросов, и дис- HANDLE CreateIoCompletionPort( петчера с очередью запросов. При наличии необработанных запросов дис- HANDLE FileHandle, HANDLE ExistingCompletionPort, петчер находит свободный поток и передает запрос этому потоку; если ULONG_PTR CompletionKey, DWORD NumberOfConcurrentThreads свободных потоков нет, то диспетчер ожидает освобождения какого-либо );
Страницы
- « первая
- ‹ предыдущая
- …
- 114
- 115
- 116
- 117
- 118
- …
- следующая ›
- последняя »