Главное отличие приведенного выше кода в том, что создается только один объект AssemblyLoadContext. В таком случае, если сборка ClassLibrary1 загружается дважды, то второй экземпляр сборки является просто указателем на ее первый экземпляр. Выполнение кода дает следующий вывод:

*** Loading Additional Assemblies in Same Context ***

Assembly1.Equals(Assembly2) True

Assembly1 == Assembly2 True

Class1.Equals(Class2) False

Class1 == Class2 False

<p id="AutBody_Root533">Итоговые сведения о процессах, доменах приложений и контекстах загрузки</p>

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

<p id="AutBody_Root534">Резюме</p>

Задачей главы было исследование особенностей обслуживания приложения .NET Core платформой .NET Core. Как вы видели, давно существующее понятие процесса Windows было внутренне изменено и адаптировано под потребности среды CoreCLR. Одиночный процесс (которым можно программно манипулировать посредством типа System.Diagnostics.Process) теперь состоит из домена приложения, которое представляет изолированные и независимые границы внутри процесса.

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

<p id="AutBody_Root535">Глава 15</p><p>Многопоточное, параллельное и асинхронное программирование</p>

Вряд ли кому-то понравится работать с приложением, которое притормаживает во время выполнения. Аналогично никто не будет в восторге от того, что запуск какой-то задачи внутри приложения (возможно, по щелчку на элементе в панели инструментов) снижает отзывчивость других частей приложения. До выхода платформы .NET (и .NET Core) построение приложений, способных выполнять сразу несколько задач, обычно требовало написания сложного кода на языке C++, в котором использовались API-интерфейсы многопоточности Windows. К счастью, платформы .NET и .NET Core предлагают ряд способов построения программного обеспечения, которое может совершать нетривиальные операции по уникальным путям выполнения, с намного меньшими сложностями.

Глава начинается с определения общей природы "многопоточного приложения". Затем будет представлено первоначальное пространство имен для многопоточности, поставляемое со времен версии .NET 1.0 и называемое System.Threading. Вы ознакомитесь с многочисленными типами (Thread, ThreadStart и т.д.), которые позволяют явно создавать дополнительные потоки выполнения и синхронизировать разделяемые ресурсы, обеспечивая совместное использование данных несколькими потоками в неизменчивой манере.

В оставшихся разделах главы будут рассматриваться три более новых технологии, которые разработчики приложений .NET Core могут применять для построения многопоточного программного обеспечения: библиотека параллельных задач (Task Parallel Library — TPL), технология PLINQ (Parallel LINQ — параллельный LINQ) и появившиеся относительно недавно (в версии C# 6) ключевые слова, связанные с асинхронной обработкой (async и await). Вы увидите, что указанные средства помогают значительно упростить процесс создания отзывчивых многопоточных программных приложений.

<p id="AutBody_Root536">Отношения между процессом, доменом приложения, контекстом и потоком</p>

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

Перейти на страницу:

Похожие книги