Чтение онлайн

на главную - закладки

Жанры

Программирование мобильных устройств на платформе .NET Compact Framework

Салмре Иво

Шрифт:

Начинайте с создания однопоточного приложения

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

В простых случаях пытайтесь обойтись без многопоточного выполнения, используя курсоры ожидания

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

Если вам предварительно известно, в каких местах программы происходит задержка, предусмотрите

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

Рассмотрите возможность использования фоновых потоков, если выполнение задачи требует длительного или неопределенного времени

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

Максимально упрощайте многопоточный код и документируйте его для повышения надежности

Безопасность многопоточной поддержки — штука хитрая. Если не уделить должное внимание тому, как осуществляется считывание и запись переменных-членов, то может случиться так, что ваше приложение будет пытаться прочитать в одном потоке переменную, запись которой была начата другим потоком, но еще не успела закончиться; "атомарность", то есть неделимость — выполнение за один раз от начала до конца, для большинства операций над данными, находящимися в памяти, не гарантируется, поскольку для записи большинства типов данных требуется выполнение нескольких инструкций микропроцессора. Тот факт, что возникновение проблем подобного рода зависит от временных характеристик выполнения потоков и случается редко, значительно затрудняет их обнаружение, воспроизведение и отладку. Даже ecли гарантирована атомарность доступа к переменным, но при этом было уделено недостаточное внимание тому, как осуществляются вызовы функций-членов классов, то вы можете оказаться в ситуации, когда либо портятся данные, либо программа ведет себя непредсказуемым образом, поскольку соответствующие данные параллельно изменяются алгоритмами, выполняющимися разными потоками; представьте, например два потока, которые одновременно пытаются вставлять и удалять записи в одном и том же связанном списке. Для надежной обработки таких ситуаций необходимо определить "критические разделы" кода; тем самым будет гарантироваться, что любой код, связанный с одним и тем же объектом семафора, сможет выполнять только одним потоком. (В C# это достигается за счет использования оператора lock(объект), а в Visual Basic — с использованием оператора SyncLock(объект). Для получения более подробной информации относительно двух указанных операторов обратитесь к библиотеке справочной документации MSDN.) Ситуацию могут еще более осложнять "зависания", или "взаимоблокировки", когда два потока, выполняющиеся в одно и то же время в разных критических разделах, вызывают код, который должен войти в критический раздел, "принадлежащий" в данный момент другому потоку; при вхождении в критический раздел другого потока будет приостановлено выполнение каждого потока. По этой причине, а также с учетом факторов производительности, чрезмерно вольное использование критических разделов может привести к появлению дополнительных проблем.

Вы могли бы попытаться сделать все свойства и методы своих классов безопасными в отношении многопоточного выполнения, однако осуществить это чрезвычайно трудно с технической точки зрения и расточительно с точки зрения производительности. В конце концов, весь код вашего приложения оказался бы испещренным множеством самых различных критических разделов и бесчисленным количеством всевозможных объектов, используемых в качестве семафоров совместно с критическими разделами. Код такого типа чрезвычайно трудно проектировать и тестировать; кроме того, он характеризуется повышенными накладными расходами, обусловленными необходимостью осуществления проверок, обеспечивающих безопасность многопоточности, и чрезмерно сериализованным выполнением. Ни в .NET Framework, ни в .NET Compact Framework попытки решения этой задачи не делаются; вместо этого в обеих средах используется подход, основанный на тщательном документировании всех возможностей, и явное объявление того, какие операции безопасны в отношении многопоточного выполнения, а какие таковыми не являются. Предполагается,

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

Аналогичный подход вам следует использовать и в своих проектах. Вы должны явно указывать в коде классы, функции и свойства, требующие доступа из нескольких потоков, и сводить их количество к минимуму. Критические разделы кода следует объявлять и использовать лишь в тех случаях, когда многопоточный доступ является абсолютно необходимым, и обнаружены проблемы параллельного выполнения или доступа к данным, устранить которые простыми методами не удается. Очень тщательно проектируйте, программируйте и тестируйте эти специальные классы и функции и столь же тщательно документируйте все свои классы, свойства и методы. Если многопоточный доступ к типу, свойству или методу не является безопасным или у вас есть сомнения относительно безопасности доступа к ним из нескольких потоков, документируйте это в своем коде. Например:

// К ДАННОЙ <ПЕРЕМЕННОЙ/СВОЙСТВУ/МЕТОДУ> ДОСТУП ИЗ НЕСКОЛЬКИХ ПОТОКОВ

// ОСУЩЕСТВЛЯТЬСЯ НЕ ДОЛЖЕН!!!

// Предполагается, что этот метод будет использоваться

// <высокоприоритетным/фоновым> потоком для ...

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

Рассмотрите возможность предварительного выполнения некоторой работы, осуществляемой кодом

Для обработки некоторых пользовательских запросов требуется довольно большое время. В качестве примера можно привести расчет или загрузку значительного количества данных, выполнение сетевого запроса или визуализацию сложных изображений в ответ на поступающие запросы. Если выполнение этих операций тормозит работу приложения, то вынужденное ожидание будет раздражать пользователя. Вы должны приложить все усилия к тому, чтобы такие ситуации не возникали. Если ваше приложение допускает возможность достаточно надежного вероятностного прогнозирования очередных действий пользователя и при этом достаточно хорошо известно, какие виды трудоемкой или длительной обработки данных могут потребоваться в ответ на эти действия, то целесообразно подумать над тем, как выполнить эту работу заблаговременно, не дожидаясь соответствующего пользовательского запроса. В качестве образной аналогии представьте себя владельцем ресторана, постоянный посетитель которого ежедневно приходит к 8 часам утра и, торопясь, заказывает яичницу из двух яиц, пирог с черникой, тарелку каши и чашку кофе. Нетрудно догадаться, что в этом случае имело бы смысл ежедневно подготавливать эти блюда к подаче в указанное время. Даже если посетитель и не придет в какой-то из дней, эта мера все равно будет оправданной, поскольку значительно повысит удовлетворенность клиента качеством обслуживания в те дни, которые им не были пропущены. Заблаговременно готовясь к немедленному оказанию услуг, как только они будут затребованы, вы сможете обеспечить уникальное высококачественное обслуживание клиентов.

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

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

Поделиться:
Популярные книги

Идеальный мир для Лекаря 19

Сапфир Олег
19. Лекарь
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 19

Сердце Дракона. Том 11

Клеванский Кирилл Сергеевич
11. Сердце дракона
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
6.50
рейтинг книги
Сердце Дракона. Том 11

Стеллар. Заклинатель

Прокофьев Роман Юрьевич
3. Стеллар
Фантастика:
боевая фантастика
8.40
рейтинг книги
Стеллар. Заклинатель

Дракон - не подарок

Суббота Светлана
2. Королевская академия Драко
Фантастика:
фэнтези
6.74
рейтинг книги
Дракон - не подарок

Девочка-яд

Коэн Даша
2. Молодые, горячие, влюбленные
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Девочка-яд

Авиатор: назад в СССР 14

Дорин Михаил
14. Покоряя небо
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Авиатор: назад в СССР 14

Метка драконов. Княжеский отбор

Максименко Анастасия
Фантастика:
фэнтези
5.50
рейтинг книги
Метка драконов. Княжеский отбор

Последний Паладин. Том 5

Саваровский Роман
5. Путь Паладина
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Последний Паладин. Том 5

Приручитель женщин-монстров. Том 5

Дорничев Дмитрий
5. Покемоны? Какие покемоны?
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Приручитель женщин-монстров. Том 5

Дайте поспать! Том II

Матисов Павел
2. Вечный Сон
Фантастика:
фэнтези
постапокалипсис
рпг
5.00
рейтинг книги
Дайте поспать! Том II

Целитель. Книга вторая

Первухин Андрей Евгеньевич
2. Целитель
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Целитель. Книга вторая

Табу на вожделение. Мечта профессора

Сладкова Людмила Викторовна
4. Яд первой любви
Любовные романы:
современные любовные романы
5.58
рейтинг книги
Табу на вожделение. Мечта профессора

Скрываясь в тени

Мазуров Дмитрий
2. Теневой путь
Фантастика:
боевая фантастика
7.84
рейтинг книги
Скрываясь в тени

Идеальный мир для Лекаря 14

Сапфир Олег
14. Лекарь
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 14