Главная » C# » Многопоточная обработка в Visual C# (Sharp)

0

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

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

Основное внимание в этой главе уделяется тому, как писать код, способный рабать в режиме многозадачности. Операционная система работает в режиме многадачности по умолчанию, но будет ли ваша программа многозадачной, зависит от того, как вы ее напишете. Допустим, что контроллер управления освещением, рамотренный в главе 8, должен контролировать освещение в 3000 комнатах. Чтобы управлять таким большим количеством комнат, нам нужно было бы исполнять паллельно один и тот же код. И вот в этом и заключается проблема кода, который должен исполняться в режиме многозадачности: заставить код работать эффектио параллельно — задача не из легких. Распространенной проблемой многозадаых приложений является взаимоблокировка.  Взаимоблокировка  происходит,  кда для продолжения работы две задачи нуждаются в данных друг от друга Это означает, что ни одна из них не может продолжать исполнение.

Чтобы написать код для параллельного исполнения, программист должен соблать определенную дисциплину кодирования, как будет показано в этой главе. Для этого нам будет достаточно только одного проекта JuggiingTasks. Проект претавляет собой консольное приложение, в котором реализуются методы, рассмаиваемые в этой главе.

Понимание многозадачности

Одним из самых больших скачков в истории компьютерных вычислений был скок, когда компьютер из машины, способной выполнять одну задачу, стал машой, способной выполнять несколько задач одновременно. Такие компьютеры, как Commodore 64 и Vic20, были однозадачными машинами. При работе с однозадаыми машинами вы включаете компьютер, и он ожидает от вас указания делать что-либо. Скажем, если вы решили, чтобы компьютер исполнил цикл в миллион итераций, выводя на экран слово "привет", то это все,  что однозадачный  компьер будет делать, рн не способен начать какую-либо задачу и, ожидая ответ от этой задачи, начать делать что-то другое. Сейчас мы можем только удивляться, как ли умудрялись что-то делать на таких компьютерах. (Но, с другой стороны, можно спорить, что, может быть, люди были более производительными, работая с одной программой, а не когда им нужно проверять электронную почту, загружать Web- страницу и печатать отчет одновременно.)

С приобретением компьютерами возможности многозадачности ситуация в облаи информационных технологий изменилась поразительно. Но серверные компьеры под управлением таких операционных систем, как UNIX, были многозадаыми с самого начала. А многозадачность операционных системы, таких как Windows, не была полностью вытесняющей до тех пор, пока не были выпущены Windows NT и Windows 95. Обратите внимание на термин "вытесняющая многадачность", который означает нечто значительно другое, чем простая многозачность.

При простой многозадачности отдельные задачи кооперируют между собой и веляют ресурсы коллективно. По существу, простая многозадачность является тиковой веткой в эволюции операционных систем. Лучшим ее примером были Windows 3.0 и Windows 3.1 (да и в тех многозадачность работала лишь благодаря множеству ручных решений индивидуальных проблем). Теперь рассмотрим, что же такое вытесняющая многозадачность.

Вытесняющая многозадачность

Термин "вытесняющая многозадачность" (preemptive multitasking)  означает, что запуск и работа приложений контролируются операционной системой. Необходимо осознавать, что операционная система сама является приложением, а другие прожения можно выполнять, потому что они рассматриваются, как компоненты операционной  системы.  Чтобы  проверить  это,  создайте  консольное  приложение,

переименуйте метод Main () в Mains () и посмотрите, что будет. В действительности метод Main о является интерфейсом API,  применяемым  операционной  системой для исполнения вашего компонента, который маскируется в виде программы.

Таким образом, мы имеем программу, называющуюся операционной системой, корая исполняет компоненты, называющиеся программами. Следующий вопрос — как  несколько  программ  могут  выполняться  одновременно?  Ответ  заключается в том, что операционная система не является простой программой, а основанием, на котором запускаются и управляются приложения. Операционная  система полючается  к   специальным  возможностям  микропроцессора,  с   помощью   котых каждой программе выделяется ее  временной  интервал  или  квант  времени. Так как программы .NET являются компонентами, им никогда не требуется прямой доступ к микропроцессору.  Более того,  операционная система не  позволит этого, т. к. это может нарушить ее целостность и стабильность работы.

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

Термин "квантование времени" (time slicing) означает, что операционная система выделяет каждой программе интервал времени для исполнения. Время выделения и длительность этого интервала определяются операционной системой полностью по своему усмотрению. Вне пределов своего интервала времени программа находится в состоянии глубокого замораживания и не делает абсолютно ничего. Но пользовелю эти периодические случаи клинической смерти  программы  незаметны, т. к. они длятся микросекунды, что создает видимость непрерывного исполнения прраммы. Посмотреть квантование времени в действии можно с помощью Windows Task Manager (Диспетчер задач Windows).

На рис. 13.1 показан пример этого окна, в котором можно видеть, что программа explorer.exe занимает 6% времени центрального процессора. Можно сказать, что общий объем квантов времени, выделяемый операционной системой приложению explorer.exe, равно 6% всего времени центрального процессора. Каким образом центральный процессор разбивает эти 6% своего времени, выделенного приложию explorer.exe, является частностью операционной системы.

Квантование времени и сопутствующие вопросы не представляют ничего сложного на одноядерных процессорах. Но на многоядерных процессорах квантование врени становится проблемой.

Скажем, что наша программа исполняет на одноядерном процессоре две задачи: задачу 1 и задачу 2. Для каждой задачи процессор выделит отдельный квант времи (рис. 13.2). На рисунке весь цикл обработки представлен в виде секторной дираммы, а каждый квант — в виде отдельного сектора.

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

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

Рис. 13.1. Квантование времени в Windows в действии

Рис. 13.2. Выполнение двух задач на одноядерном процессоре

Рис. 13.3. Выполнение двух задач на многоядерном процессоре

Теперь посмотрим на рис. 13.3, где показано то же самое приложение, но выпояющееся на многоядерном процессоре.

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

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

ПРИМЕЧАНИЕ

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

Источник: Гросс  К. С# 2008:  Пер. с англ. — СПб.:  БХВ-Петербург, 2009. — 576 е.:  ил. — (Самоучитель)

По теме:

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