Глава.27 .Асинхронные.вычислительные.операции
Впрочем, возможен и такой результат:
Main thread: queuing an asynchronous operation
In ComputeBoundOp: state=5
Main thread: Doing other work here...
Разный порядок следования строк в данном случае объясняется асинхронным
выполнением методов. Планировщик Windows решает, какой поток должен вы-
полняться первым, или же планирует их для одновременного выполнения на
многопроцессорном компьютере.
ПриМеЧание
Если.метод.обратного.вызова.генерирует.необработанное.исключение,.CLR.заверша-
ет.процесс.(если.это.не.противоречит.политике.хоста) .Необработанные.исключения.
обсуждались.в.главе.20
ПриМеЧание
В.приложениях.Windows.Store.класс.System Threading ThreadPool.недоступен.для.
открытого.использования .Впрочем,.он.косвенно.используется.при.использовании.
типов.из.пространства.имен.System Threading Tasks.(см .раздел.«Задания».далее.
в.этой.главе)
Контексты исполнения
С каждым потоком связан определенный контекст исполнения. Он включа-
ет в себя параметры безопасности (сжатый стек, свойство
Principal
объекта
Thread
и идентификационные данные Windows), параметры хоста (
System.
Threading.HostExecutionContextManager
) и контекстные данные логического
вызова (см. методы
LogicalSetData
и
LogicalGetData
класса
System.Runtime.
Remoting.Messaging.CallContext
). Когда поток исполняет код, значения параме-
тров контекста исполнения оказывают влияние на некоторые операции. В идеале
всякий раз при использовании для выполнения заданий вспомогательного потока
в этот вспомогательный поток должен копироваться контекст исполнения перво-
го потока. Это гарантирует использование одинаковых параметров безопасности
и хоста в обоих потоках, а также доступ вспомогательного потока к данным, со-
храненным в контексте логического вызова исходного потока.
По умолчанию CLR автоматически копирует контекст исполнения самого
первого потока во все вспомогательные потоки. Это гарантирует безопасность,
но в ущерб производительности, потому что в контексте исполнения содержится
много информации. Сбор всей информации и ее копирование во вспомогательные
потоки занимает немало времени. Вспомогательный поток может, в свою очередь,
751
Контексты.исполнения
использовать вспомогательные потоки, при этом создаются и инициализируются
дополнительные структуры данных.
Класс
ExecutionContext
в пространстве имен
System.Threading
позволяет
управлять копированием контекста исполнения потока. Вот как он выглядит:
public sea
led class ExecutionContext : IDisposable, ISerializable {
[SecurityCritical] public static AsyncFlowControl SuppressFlow();
public static void RestoreFlow();
public static Boolean IsFlowSuppressed();
// Не показаны редко применяемые методы
}
С помощью этого класса можно запретить копирование контекста исполнения,
повысив производительность приложения. Для серверных приложений рост про-
изводительности в этом случае оказывается весьма значительным. Для клиентских
приложений особой выгоды нет, кроме того, метод
SuppressFlow
помечается атри-
бутом
[SecurityCritical]
, в результате становится невозможным вызов некоторых
клиентских приложений (например, Microsoft Silverlight). Разумеется, запрещать
копирование контекста исполнения можно, только если вспомогательному пото-
ку не требуется содержащаяся там информация. Когда инициирующий контекст
исполнения не переходит во вспомогательный поток, тот использует последний
связанный с ним контекст исполнения. Поэтому при отключенном копировании
контекста поток не должен исполнять код, зависящий от состояния текущего кон-
текста исполнения (например, идентификационных данных пользователя Windows).
Следующий пример демонстрирует, как запрет на копирование контекста ис-
полнения влияет на данные в контексте логического вызова потока при постановке
рабочего элемента в очередь в CLR-пуле
1
:
public static void Main() {
// Помещаем данные в контекст логического вызова потока метода Main
CallContext.LogicalSetData("Name", "Jeffrey");
// Заставляем поток из пула работать
// Поток из пула имеет доступ к данным контекста логического вызова
ThreadPool.QueueUserWorkItem(
state => Console.WriteLine("Name={0}",
CallContext.LogicalGetData("Name")));
// Запрещаем копирование контекста исполнения потока метода Main
ExecutionContext.SuppressFlow();
// Заставляем поток из пула выполнить работу.
// Поток из пула НЕ имеет доступа к данным контекста логического вызова
ThreadPool.QueueUserWorkItem(
1
Добавляемые к контексту логического вызова элементы должны быть сериализуемыми
(см. главу 24). Копирование контекста исполнения, содержащего данные контекста логи-
ческого вызова, крайне отрицательно сказывается на производительности, так как требует
серилизации и десериализации всех элементов данных.
продолжение
752
Do'stlaringiz bilan baham: |