Рекомендации по многопоточному программированию
Для эффективного многопоточного программирования самое главное — мыслить категориями параллельного, а не последовательного выполнения кода. Так, если в одной программе имеются две подсистемы, которые могут работать параллельно, их следует организовать в отдельные потоки. Но делать это следует очень внимательно и аккуратно, поскольку если создать слишком много потоков, то тем самым можно значительно снизить,.а не повысить производительность программы. Следует также иметь в виду дополнительные издержки, связанные с переключением контекста. Так, если создать слишком много потоков, то на смену контекста уйдет больше времени ЦП, чем на выполнение самой программы! И наконец, для написания нового кода, предназначенного для многопоточной обработки, рекомендуется пользоваться библиотекой распараллеливания задач (TPL), о которой речь пойдет в следующей главе.
Запуск отдельной задачи
Многозадачность на основе потоков чаще всего организуется при программировании на С#. Но там, где это уместно, можно организовать и многозадачность на основе процессов. В этом случае вместо запуска другого потока в одной и той же программе одна программа начинает выполнение другой. При программировании на C# это делается с помощью класса Process, определенного в пространстве имен System. Diagnostics. В заключение этой главы вкратце будут рассмотрены особенности запуска и управления другим процессом.
Простейший способ запустить другой процесс — воспользоваться методом Start (), определенным в классе Process. Ниже приведена одна из самых простых форм этого метода:
public static Process Start(string имя_файла)
где имя_файла обозначает конкретное имя файла, который должен исполняться или же связан с исполняемым файлом.
Когда созданный процесс завершается, следует вызвать метод Close (), чтобы освободить память, выделенную для этого процесса. Ниже приведена форма объявления метода Close ().
Public void Close ()
Процесс может быть прерван двумя способами. Если процесс является приложением Windows с графическим пользовательским интерфейсом, то для прерывания такого процесса вызывается метод CloseMainWindow (), форма которого приведена ниже.
Public bool CloseMainWindow()
Этот метод посылает процессу сообщение, предписывающее ему остановиться. Он возвращает логическое значение true, если сообщение получено, и логическое значение false, если приложение не имеет графического пользовательского интерфейса или главного окна. Следует, однако, иметь в виду, что метод CloseMainWindow () служит только для запроса остановки процесса. Если приложение проигнорирует такой запрос, то оно не будет прервано как процесс.
Для безусловного прерывания процесса следует вызвать метод Kill (), как показано ниже.
Public void Kill()
Но методом Kill () следует пользоваться аккуратно, так как он приводит к неконтролируемому прерыванию процесса. Любые несохраненные данные, связанные с прерываемым процессом, будут, скорее всего, потеряны.
Для того чтобы организовать ожидание завершения процесса, можно воспользоваться методом WaitForExit (). Ниже приведены две его формы.
Public void WaitForExit()
public bool WaitForExit(int миллисекунд)
В первой форме ожидание продолжается до тех пор, пока процесс не завершится, а во второй форме — только в течение указанного количества миллисекунд. В последнем случае метод WaitForExit () возвращает логическое значение true, если процесс завершился, и логическое значение false, если он все еще выполняется.
В приведенном ниже примере программы демонстрируется создание, ожидание и закрытие процесса. В этой программе сначала запускается стандартная сервисная программа Windows: текстовый редактор WordPad.exe, а затем организуется ожидание завершения программы WordPad как процесса.
// Продемонстрировать запуск нового процесса.
Using System;
Using System.Diagnostics;
class StartProcess { static void Main() {
Process newProc =r Process.Start("wordpad.exe");
Console.WriteLine("Новый процесс запущен.");
NewProc.WaitForExit();
newProc.Close(); // освободить выделенные ресурсы Console.WriteLine("Новый процесс завершен.");
}
}
При выполнении этой программы запускается стандартное приложение WordPad, и на экране появляется сообщение "Новый процесс запущен. ". Затем программа ожидает закрытия WordPad. По окончании работы WordPad на экране появляется заключительное сообщение "Новый процесс завершен.11.
ГЛАВА 24 Многопоточное программирование. Часть вторая: библиотека TPL
Вероятно, самым главным среди новых средств, внедренных в версию 4.0 среды.NET Framework, является библиотека распараллеливания задач (TPL). Эта библиотека усовершенствует многопоточное программирование двумя основными способами. Во-первых, она упрощает создание и применение многих потоков. И во-вторых, она позволяет автоматически использовать несколько процессоров. Иными словами, TPL открывает возможности для автоматического масштабирования приложений с целью эффективного использования ряда доступных процессоров. Благодаря этим двух особенностям библиотеки TPL она рекомендуется в большинстве случаев к применению для организации многопоточной обработки.
Еще одним средством параллельного программирования, внедренным в версию 4.0 среды.NET Framework, является параллельный язык интегрированных запросов (PLINQ). Язык PLINQ дает возможность составлять запросы, для обработки которых автоматически используется несколько процессоров, а также принцип параллелизма, когда это уместно. Как станет ясно из дальнейшего, запросить параллельную обработку запроса очень просто. Следовательно, с помощью PLINQ можно без особого труда внедрить параллелизм в запрос.
Главной причиной появления таких важных новшеств, как TPL и PLINQ, служит возросшее значение параллелизма в современном программировании. В настоящее время многоядерные процессоры уже стали обычным явлением.