Нэш Трей - C# 2010. Ускоренный курс для профессионалов (2010) (1160865), страница 107
Текст из файла (страница 107)
Вместо него должны применяться типы-наследники Яагенапсг1е. Тип Багензпсг1е также использует ограниченные области выполнения, чтобы предотвратить утечки ресурсов в случае асинхронных исключений вроде тпгезбАЬогсехсерг1оп. Подробнее об ограниченных областях выполнения читайте в главе 7. В предыдущем примере метод сгезсееуепг объявлен как возвращающий яагеиз1тнапсс1е.
Хотя зто не очевидно из документации по ЯзгеНапсг1е, данный класс имеет приватный конструктор по умолчанию, который уровень Р/!пчохе может использовать для создания и инициализации экземпляра этого класса. Ознакомьтесь с остальными типами, производными от Бзгензпб1е, которые определены в пространстве имен м»сгозогг.и1п32. Бзтензпб1ез. В частности, в .
МЕТ 20 Ргзгленог!с для удобства определения собственных основанных на УУ!п32 наследников Бзгеиа1тнзпб1е предлагаются типы язгензпб1ем1пизОпе1зтпуз11б и Багеняпб1ееегобгм1пизбпе1з1пуа11сн Они очень удобны, поскольку, к сожалению, для представления ошибочных ситуаций в различных подразделах !Мп32 АР! используются разные значения возвращаемых дескрипторов. Имейте в виду, что тип ИаТСНапб1е реализует интерфейс 101зрозаЬ1е. В связи с этим всякий раз, когда в коде используются экземпляры Изгаизпб1е или любых его классов-наследников, таких какнцкех, Аотокезетнуепг и Мапиа1незеГЕуепт, разумно применять ключевое слово пз1псг.
Еще один момент, связанный с использованием объектов ИзТГНапсг1е и его наследников: когда управляемые потоки заблокированы методами Иа»СНапб1е. завершить или прервать их не удастся. Поскольку действительный поток операционной системы, который стоит за управляемым потоком, блокируется внутри ОС, т.е.
вне управляемой исполняющей среды, он может быть прерван только тогда, когда вернется в управляемую среду. Поэтому в случае вызова АЬогг нли 1птеггпрт на одном из этих потоков 402 Глава 12 операция будет отложена до тех пор, пока не завершится ожидание потока на уровне операционной системы. Об этом следует помнить при установке блокировки с использованием объекта Ха1г напб1е в управляемых потоках. Использование тЬхеайРоо1 Пул потоков — идеальное средство в системе, где небольшие единицы работы выполняются регулярно в асинхронном режиме.
Хорошим примером может служить вебсервер или сервер любого иного рода, который прослушивает запросы, поступающие на сетевой порт. Когда приходит запрос, выделяется новый поток, которому запрос передается на обработку. Обслуживая зти запросы в нескольких потоках, сервер достигает высокой степени параллелизма и оптимальной утилизации. Обычно медленнее всех выполняются операции ввода-вывода. Устройства хранения, подобные жестким дискам, работают очень медленно по сравнению с процессором и его возможностями обращения к памяти.
Поатому для оптимизации использования системы можно начинать выполнение других элементов работы, пока идет ожидание завершения операции ввода-вывода в другом потоке. Создание пула потоков для управления такой системой — сложнейшая задача, изобилующая массой деталей и ловушек. Однако среда .1ЧЕТ предлагает готовый к использованию пул потоков в форме класса ТЬгеабРоо1. Класс ТЬгеабРоо1 подобен классам Мопагог и тпгег1осхеб в том смысле,что создавать его экземпляры нельзя.
Вместо этого для управления пулом потоков, который каждый процесс получает по умолчанию от СЬК, применяются статические методы класса ТЬгеабРоо1. Фактически о создании пула потоков даже не нужно заботиться. Он создается при первом обращении к нему. Если вы использовали пулы потоков в мире %Чп32 — будь то системный пул потоков, который появился в Ю!пбоиз 2000. или порты завершения ввода-вывода. — то заметите, что пул потоков .НЕТ аналогичен, но имеет управляемый интерфейс. Чтобы поставить в очередь элемент в пул потоков, необходимо просто вызвать ТЬгеабРоо1.
0оеоебзегиогХ1ген, передав ему экземпляр делегата Ха1ССа11Ьасх. Пул потоков создается при первом вызове этой функции. Метод обратного вызова, представленный делегатом Ха1ССа11Ьасх, принимает ссылку на экземпляр Бузсеа.ОЬ1есе и имеет тип возврата чо1б. Объектная ссылка — необязательный объект контекста, который вызывающий код может применить к перегрузке 0оеоебзегногЬ1сет. Если контекст не указан, то ссылка на контекст должна быть па11. После помещения элемента работы в очередь поток из пула осуществит обратный вызов, как только станет доступным. Когда элемент работы помещается в очередь, он уже никак не может быть удален оттуда, кроме как посредством потока, который завершит выполнение этой единицы работы. Поэтому, если требуется отменить выполнение элемента работы, нужно предусмотреть способ уведомить обратный вызов, что он не должен ничего делать, когда будет вызван.
Пул потоков настроен на максимально эффективную обработку рабочих элементов. Для определения количества потоков, которые нужно создать, пул использует алгоритм, основанный на том, сколько процессоров доступно в системе. Однако даже после этого пул может содержать больше потоков, чем изначально вычислено. Например, предположим, что алгоритм решает, что пул потоков должен содержать в себе четыре потока. Затем предположим, что сервер принимает четыре запроса, требующих обращения к базе данных, отнимающих определенное время. Если в течение этого времени поступит пятый запрос, свободных потоков для его обслуживания, не окажется. Еще хуже то, что четыре занятых потока в это время просто ждут завершения операций ввода-вывода. Чтобы заставить систему работать с максимальной производительностью, пул потоков ()(ногопогочность з С» 403 в действительности создаст еще один поток, когда обнаружит,что все прочие заблокированы.
После завершения всех единиц работы, когда система вернется в устойчивое состояние, пул потоков избавится от дополнительных потоков, созданных подобным образом, уничтожив их. Несмотря на невозможность простого управления количеством потоков в пуле, с помощью вызовов ОеСМзпТЬгеаба и ЯеСМТпТЬгеабз можно контролировать минимальное число простаивающих потоков, которые ожидают работы. Если планируется непосредственная работа с пулом потоков, рекомендуется изучить описание статических методов Яузгев. ТЬгеаб1пд. ТЬгеаброо1 в документации МЭП))).
В действительности необходимость в прямой вставке рабочих элементов в пул потоков возникает редко. Существует другая, более элегантная точка входа в пул потоков через делегаты и вызовы асинхронных процедур, о которой речь пойдет в следующем разделе. Асинхронные вызовы методов Хотя управлять помещением элементов работы в пул потоков можно непосредственно через класс ТЬгеаброо1, более популярный способ использования пула потоков заключается в вызовах асинхронных делегатов.
При объявлении делегата СЬ)1 создает класс-наследник Яузгев. Мп1СТсазСОе1едаге. Один из определенных в нем методов, 1пчо)се, принимает точно ту же сигнатуру функции, что и определение делегата. Разумеется в С» предусмотрено синтаксическое сокращение для вызова метода 1пчоке. Но наряду с 1пчо)се среда СЕЙ также определяет два метода Вед1п1пчо)се и Епб1пчо)се, являющиеся сердцем шаблона асинхронной обработки, которая используется СЬК. Этот шаблон подобен шаблону 101), который был представлен ранее в этой главе. Базовая идея очевидным образом исходит из имен методов.
При вызове Вед1п1пчо)се на делегате операция откладывается для выполнения в другом потоке. Вызове метода Епб1пчо)се приводит к возврату результатов операции. Если операция не завершена на момент вызова Епб1пчо)се, вызывающий поток блокируется до тех пор, пока она не будет завершена. Рассмотрим краткий пример, демонстрирующий общий шаблон в действии. Предположим, что есть метод, вычисляющий сумму налогов за год, и его требуется вызывать асинхронно, потому что его выполнение занимает ощутимое время. из1п9 Яуагев) пз»пч Яузгев.ТЬгеаб1пд) риЬ11с с1ааз БпггуРо»пС ( 11 Объявление делегата для асинхронного вызова.
рг1чаге бе1е9аге Оес1ва1 СоврпгеТахезпе1едаге( 1пс уеаг )) 11 Метод для вычисления налогов. рссчаге агаС1с Рес»ва1 СоврпгеТахеа( ТпС уеаг ) ( Сопао1е.иг1Се11пе( "Вычисление налогов в потоке (О)", ТЬгеаб.спггепСТЬгеаб.Мападебтпгеаб1б ) 11 Здесь происходит длительное вычисление. ТЬгеаб.Я1еер( 6000 )) гегпгп 4356.98М; аСаСТс чо1б Ма»п() ( 11 Выполним асинхронный вызов, создав делегат и вызвав его. Соврпгетахеапе1ечаге ногК = пен СоврпгеТахезпе1ечаге( ЕпггуРо»пС.СовригеТахеа )) 1лзупскезп1С репб»пдор ног)с.Ве91п1пчохе( 2004, пн11, пп11 ); 404 Глава (2 О Выполнить другую полезную работу.
тпгеаб.з1еер( 3000 ГГ Завершить асинхронный вызов. Сопзо1е.нгаге11пе( "Ожидание завершения операции." Оесаша1 гезц1с = ногК.Епс(1пчохе( репбапдор )г Сопэо1е.нгасеЬ1пе( "Сумма налогов: (О)", гезц11 Первое, что заметно в шаблоне — зто то, что сигиатура метода Вес1п1пчохе ие соответствует методу 1пчо)се. Это обьясияется тем, что нужен некоторый способ идентификации определенного элемента работы, который только что был отложен вызовом Вео1п1пчохе. Таким образом, Вео1п1пчохе возвращает ссылку иа объект, реализующий интерфейс 1Азупскевц10.
Этот объект подобен соо)пе-набору, который сохраняется для идентификации выполняющегося элемента работы. Через методы интерфейса 1Азупскезц1С можно проверять состояние операции, например, ее готовность. Чуть дальше этот интерфейс рассматривается более подробно; там же описаны два параметра, добавленные в конец объявления метода Вео1п1пчо)се, вместо которых было подставлено пц11. Когда поток, запрошеииый для выполнения операции, завершит свою работу, ои вызывает ЕпсПЬ го)се иа делегате. Однако, поскольку метод должен иметь способ идентификации асинхронной операции, результат которой нужно получить. ему должен быть передан объект, полученный из метода вес1п1пчо)се. В данном примере вызов Епс(1пчохе будет заблокирован иа некоторое время, до окончания операции. На заметку! Если в процессе асинхронного выполнения в пуле потоков целевого кода делегата будет сгенерировано исключение, оно сгенерируется повторно, когда инициирующий поток вызовет Епс)1пчохе.
Отчасти красота асинхронного шаблона )О)). реализованного делегатом, заключается в том, что вызванный код даже может ие знать о том, что ои вызван асинхронно. Конечно, вызывать метод асинхронно ие слишком практично, если ои для этого ие был предназначен, если ои затрагивает данные системы, к которым обращаются другие методы, либо если ие используются какие-то механизмы синхронизации. Тем ие менее, вся головная боль, связанная с созданием инфраструктуры асинхронного вызова метода, смягчается благодаря делегату, сгенерированному СЕВ, наряду с пулом потоков, связанным с процессом. Более того, инициатор асинхронного действия даже ие обязан знать, как реализовано асинхронное поведение.










