2. Практическое проектирование надежных алгоритмов параллельных вычислений представляет собой непростую задачу. Разбиение вычислений на ряд независимых ветвей выполнения и их эффективная координация весьма затруднительны и являются предметом непрекращающихся исследований. Если несколько потоков выполняют различные части одной и той же задачи, то существует значительный риск того, что они где-то пересекутся, пытаясь одновременно получить доступ к одной и той же области памяти или стремясь использовать некоторый ресурс, не допускающий параллельного доступа.
Параллельное выполнение лучше всего применять тогда, когда параллельные задачи не могут мешать друг другу. Именно поэтому серверы нередко только выигрывают от использования нескольких процессоров; серверы часто обслуживают множество независимых и не вступающих между собой в конфликт клиентских запросов. Серверы, располагающие несколькими процессорами, способны параллельно отвечать на многочисленные запросы, одновременно поступающие от разных клиентов. Параллельные задачи, выполнение которых запрашивается, часто связаны только с операциями чтения или изменением данных, которые не перекрываются между собой. Оба вида задач хорошо соответствуют идее параллельных вычислений. Приложения, выполняющиеся на таких серверах, часто располагают пулами потоков, или потоковыми пулами, используемыми для диспетчеризации поступающих запросов.
Приложения с многофункциональными клиентскими пользовательскими интерфейсами обычно не относятся к категории тех, для которых разделение работы на параллельно выполняющиеся части легко осуществить, поскольку такие приложения обычно используются для того, чтобы предоставить возможность одному пользователю работать с набором взаимосвязанных данных и элементами пользовательского интерфейса. Задача приложения, ориентированного на настольные компьютеры, как правило, состоит также в том, чтобы как можно эффективнее реагировать на запросы пользователя, а не служить многим пользователям, соперничающим между собой за разделение процессорного времени между независимыми параллельными задачами.
Если в приложении имеются операции, которые могут выиграть от выполнения в асинхронном режиме, то использование нескольких потоков может оказаться целесообразным независимо от количества установленных процессоров. Основной вопрос заключается в том, стоят ли преимущества асинхронного выполнения тех затрат, с которыми будет связано дополнительное усложнение вашего приложения. Наличие нескольких процессоров на клиентских вычислительных устройствах означает наличие дополнительных рабочих рук, что способствует повышению общей производительности устройства. В случае "толстых" клиентов рассматривать эти процессоры как выделенные ресурсы, которые могут назначаться различным частям вашего приложения, имеет смысл лишь в редких случаях.
В каких случаях следует использовать фоновые потоки
Вообще говоря, один поток в вашем приложении должен быть основным. Этот поток должен управлять пользовательским интерфейсом приложения, а когда все активные окна закроются, приложение должно завершить выполнение. При завершении приложения обычно требуется уведомить все выполняющиеся фоновые потоки о необходимости прекратить выполнение, и когда не останется ни одного открытого окна приложения, которое требовало бы поддержки со стороны основного потока и оставляло его активным, он может прекратить свое выполнение. (В этот момент осуществляется выход из функции main() приложения и управление передается обратно среде времени выполнения и операционной системе для окончательного освобождения памяти от данных приложения.) Наличие нескольких потоков, управляющих собственными окнами пользовательского интерфейса, существенно усложняет описанную модель, и этого следует избегать.
Иногда для выполнения некоторых операций, запрошенных пользователем, может требоваться значительное или неопределенное время. Если это время исчисляется несколькими секундами, то, вероятно, целесообразно вывести на экран курсор ожидания и выполнять операцию в синхронном режиме с использованием потока пользовательского интерфейса. Если же для этого требуется большее или неопределенное время, то подходящим решением будет передача выполнения этой работы фоновому потоку. Это может быть сделано двумя способами:
Читать дальше