Главная » Silverlight » Назначение многопоточности

0

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

Ниже перечислены три главные причины использования в программе многих потоков.

•       Чтобы клиентское приложение всегда немедленно реагировало на действия пользователя. Если приложение выполняет длительную задачу, она захватывает процессор, и приложение перестает реагировать на действия пользователя. Ему приходится ждать, пока закончится выполнение вспомогательной задачи. Поль­зователям такое поведение программы, естественно, не понравится. Радикальное решение проблемы состоит в направлении (маршаллизации) вспомогательной за­дачи в другой поток, в результате чего интерфейс, обслуживаемый первым пото­ком, будет немедленно реагировать на действия пользователя. Можно также пре­доставить пользователю возможность отменить вспомогательную задачу в любой момент, когда она еще не завершена.

•       Для решения нескольких задач одновременно. При использовании типичного однопроцессорного компьютера многозадачность сама по себе не повышает про­изводительность. Фактически производительность даже немного уменьшается вследствие накладных расходов на создание потоков. Однако для многих задач ха­рактерны существенные интервалы бездействия процессора. Например, процес­сор работает не все время при загрузке данных из внешнего источника (веб-сайта, базы данных и т.д.) или при коммуникации с отдаленным компонентом. Когда вы­полняются эти задачи, процессор большую часть времени не занят. Уменьшить время ожидания нельзя, потому что оно определяется пропускной способностью канала и производительностью сервера, однако можно полнее загрузить процес­сор другими задачами. Например, можно одновременно передать запросы трем разным веб-службам, уменьшив таким образом общее время ожидания.

•       Для обеспечения расширяемости приложения на стороне сервера. Сервер­ная часть приложения должна одновременно обслуживать произвольное (обыч­но большое) количество клиентов. Одновременность обеспечивается серверной технологией (например, ASP.NET). Разработчик приложений Silverlight может соз­дать собственную инфраструктуру серверной части. Например, в главе 20 рас­сматривается создание приложений на основе сокетов и сетевых классов .NET. Однако подобные технологии обычно касаются серверных приложений, а не при­ложений Silverlight.

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

Совет. Быстродействие процессора редко бывает лимитирующим фактором производительности приложения Silverlight. Обычно производительность ограничивается низкой пропускной способностью каналов, медлительностью веб-служб, необходимостью частого обращения к диску и другими лимитирующими факторами. В результате многопоточность редко улучшает общую производительность, даже при использовании двухъядерного процессора. Поэтому в приложениях Silverlight многопоточность полезна главным образом для обеспечения постоянной готовности интерфейса.*

Класс DispatcherTimer

Содержащийся в пространстве имен System.Windows.Threading класс Dispatcher- Timer позволяет избежать многих проблем, связанных с многопоточностью. В главе 10 он использовался в игре с перехватом бомб.

Класс DispatcherTimer не создает потоки. Вместо этого он периодически генериру­ет событие Tick в главном потоке приложения. Событие Tick прерывает выполнение кода в любой точке, в которой оно застало код, и предоставляет возможность запустить иную задачу. Если нужно часто выполнять небольшие коды (например, запускать но­вые анимации каждые полсекунды), класс DispatcherTimer работает так же бесшовно, как классы действительной многопоточности.

Піавное преимущество класса DispatcherTimer состоит в том, что событие Tick всег­да генерируется только в главном потоке приложения. Благодаря этому устраняются проблемы синхронизации потоков и другие неприятности, рассматриваемые далее. Однако появляется ряд ограничений. Например, если код обработки событий тайме­ра выполняет трудоемкую задачу, пользовательский интерфейс блокируется, пока она не закончится. Следовательно, таймер не обеспечивает постоянную готовность поль­зовательского интерфейса и не позволяет сократить время ожидания при выполнении операций, содержащих интервалы простаивания процессора. Для решения этих задач необходимо применить истинную многопоточность.

Тем не менее в некоторых ситуациях класс DispatcherTimer при умелом исполь­зовании позволяет достичь желаемых эффектов. Например, с его помощью рекомен­дуется периодически проверять веб-службы на наличие новых данных. Вызовы веб- служб выполняются асинхронно в фоновом потоке (см. главу 15). Следовательно, класс DispatcherTimer можно использовать в приложении для периодической загрузки дан­ных из медлительных веб-служб. Например, можно задать генерацию событий Tick каждые несколько минут. Вследствие того что веб-служба вызывается асинхронно, за­грузка будет выполняться в фоновом потоке.

Класс Thread

Наиболее простой способ создания многопоточного приложения Silverlight состоит в использовании класса Thread, содержащегося в пространстве имен System.Threading. Каждый объект Thread представляет один поток.

Для создания объекта Thread нужно предоставить делегат методу, вызываемому асинхронно. Объект Thread указывает только на один метод. Сигнатура метода жестко ограничена. Он не может возвращать значение. Кроме того, он либо не должен иметь параметров (для делегата ThreadStart), либо должен иметь один объектный параметр (для делегата ParameterizedThreadStart).

Предположим, необходимо вызвать метод.

private void DoSomething ()

{ … )

Создайте для него объект потока thread.

ThreadStart asyncMethod = new ThreadStart (DoSomething) ; Thread thread = new Thread(asyncMethod);

После этого запустите поток, вызвав метод Thread. Start (). Если поток принимает объектный параметр, его следует передать методу Start (). Ниже приведен оператор, запускающий поток без параметров.

thread.Start () ;

Метод start () немедленно возвращается (не завершаясь), и код начинает выпол­няться асинхронно в новом потоке. Когда метод завершается, поток уничтожается и не может быть использован повторно. Во время выполнения потока его свойства и методы (табл. 19.1) можно использовать для управления выполнением.

Таблица 19.1. Члены класса Thread

Имя

Описание

IsAlive

Это свойство имеет значение false, когда поток остановлен, уничтожен или еще не запущен

ManagedThreadld

Целое число, уникально идентифицирующее поток

Name

Строка, идентифицирующая поток; полезна, главным образом, для отладки приложения, но может быть использована и в рабочем режиме для идентификации потока; после первой установки свойства Name установить его повторно нельзя

ThreadState

Комбинация значений, указывающих на состояние потока (запущен, выполняется, завершен, остановлен и т.д.); используется только для отладки

Start ()

Запуск потока на выполнение в первый раз; метод start О нельзя использовать для повторного запуска потока после его завершения

Join ()

Ожидание завершения потока или истечения заданного интервала времени

Sleep ()

Приостановка текущего потока на заданное количество миллисекунд; этот метод статический

Примечание. Опытные программисты .NET заметят в версии Silverlight класса Thread отсутствие нескольких деталей. В Silverlight все потоки являются фоновыми. Им нельзя присвоить приоритеты. Кроме того, хотя класс Thread содержит метод Abort (), уничтожающий поток с необработанным исключением, этот метод отмечен атрибутом SecurityCritical. Поэтому он может быть вызван только надстройкой Silverlight, но не кодом приложения.

При программировании потоков главная трудность состоит в обеспечении коммуни­кации между фоновым потоком и главным потоком приложения. Передать информацию в фоновый поток несложно с помощью параметров при его запуске. Однако обмен ин­формацией с потоком, когда он выполняется, и возвращение данных при завершении потока — сложные задачи. Чтобы предотвратить одновременное обращение к одним и тем же данным из двух разных потоков, часто приходится использовать блокировки. Для предотвращения доступа фонового потока к элементам пользовательского интер­фейса используется диспетчеризация. Хуже всего то, что ошибки потоков не порожда­ют предупреждения и ошибки во время компиляции, а во время выполнения не всегда приводят к аварийному завершению. Часто они порождают тонкие, незаметные, про­блемы, не проявляющиеся во время диагностики. Правила безопасного применения по­токов рассматриваются в следующих разделах.

Источник: Мак-Дональд, Мэтью. Silverlight 3 с примерами на С# для профессионалов. : Пер. с англ. —- М. : ООО «И.Д. Вильяме», 2010. — 656 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии