Вначале существовала Java. Но затем, примерно в 2000 году, появилась бета-версия .NET, возможно, из-за отказа от судебного процесса 1997 года, поданного Sun Microsystems.
Несмотря на то, что код, написанный с использованием ранней реализации C# и Java, на первый взгляд выглядел почти идентично, несколько вещей сделали .NET по-настоящему уникальным.
Хотя в Интернете есть много материалов по .NET, большая их часть содержит проблемы, такие как:
В этом блоге мы сосредоточимся на основных вопросах, связанных с .NET Framework, включая некоторые, связанные с недавними обновлениями .NET, вплоть до выпуска 9. Мы постараемся не зацикливаться на деталях, связанных с языком.
Чтобы убедиться, что вопросы, затронутые в этом блоге, уникальны, мы специально выбрали вопросы, требующие навыков программирования как минимум среднего уровня и опыта программирования не менее трех лет. Хотя вопросов, касающихся конкретного языка, не существует, вам необходимо базовое понимание хотя бы одного языка программирования в .NET.
Итак, вам не терпится узнать больше? Давайте начнем.
Давайте сначала разберемся, что такое модуль и в чем разница между управляемым и неуправляемым модулем.
Когда мы компилируем файлы исходного кода в Microsoft .NET, мы получаем модуль, будь то на любом из многочисленных поддерживаемых языков, включая C ++, C # (произносится как C Sharp), Iron Python или Visual Basic.
Управляемый модуль – это, проще говоря, стандартный переносимый исполняемый файл Windows 32 или Windows 64-разрядной версии. Единственное отличие заключается в том, что для его выполнения требуется CLR (среда выполнения common language runtime).
Управляемый модуль состоит из четырех частей: метаданных, заголовка переносимого исполняемого файла, заголовка CLR и кода IL (промежуточного языка).
Давайте кратко обсудим каждый из них далее.
Заголовок файла для стандартного файла Windows основан на формате, обычно называемом Common Object File Format (COFF). В случае PE32 файл может быть выполнен либо в 32-, либо в 64-разрядной Windows. Заголовок PE32 + в файле подразумевает, что файл может быть выполнен только в 64-разрядной Windows.
Некоторые элементы в заголовке включают:
Заголовок CLR содержит информацию, которая делает управляемый модуль тем, что он есть. Например, он может содержать версию CLR, некоторые флаги и метод точки входа в модули (например, main). Кроме того, он может содержать другие элементы, такие как определение ресурсов, флагов и местоположения метаданных модуля.
Одна вещь, которая отличает управляемый модуль, – это раздел метаданных, в котором размещены таблицы метаданных.
В основном они бывают двух основных типов: с описанием типа / членами, определенными в коде или упомянутыми в нем.
Это фактический код, созданный компилятором из исходного кода, который преобразуется в собственные инструкции процессора при выполнении кода.
По умолчанию компилятор Microsoft создает код под названием безопасный код. Это означает, что он поддается проверке, поскольку соответствует правилам управляемого выполнения, таким как правила, связанные со сборкой мусора .Среда выполнения NET. В частности, проверка проверяет безопасность кода. Среди прочего, они включают проверку соответствия количества и типа параметров в методах и возвращаемых типах.
Однако небезопасный код может обойти эти проверки и получить прямой доступ к адресам. Таким образом, это палка о двух концах. С одной стороны, это позволяет использовать код в обход правил; при неосторожном использовании это может привести к некоторым из тех же проблем, для решения которых была разработана Microsoft .NET.
Из-за рисков, связанных с использованием unsafe, его необходимо пометить определенным ключевым словом или с помощью переключателя компилятора.
Способ, которым это работает, тесно связан с компилятором JIT (точно в срок), который преобразует IL в машинный код.
Для небезопасных методов JIT-компилятор имеет правильные разрешения на выполнение. Только в этом случае JIT-компилятор разрешит компиляцию и выполнение небезопасного кода.
Да, это можно сделать по-разному.
Во-первых, внутри называется .NET Framework Ngen.exe. Поскольку этот код предварительно скомпилирован, нет необходимости делать то же самое во время выполнения.
Затем есть .NET native, который является более новым методом.
Наконец, существует кросс-компиляция, которая позволяет создавать исполняемый код для платформы, отличной от той, на которой запущен компилятор.
Использование машинного кода имеет два конкретных преимущества. Во-первых, это может сократить время начального запуска. Во-вторых, это может сократить рабочий набор приложения, поскольку изначально скомпилированный фрагмент кода может быть передан процессам.
Всякий раз, когда мы создаем программу, для ее создания требуются различные ресурсы. Они могут быть связаны с памятью (например, буферами), на основе экрана (например, пространством экрана), на основе сети (например, подключениями) и на основе базы данных (например, подключениями).
Если мы хотим их использовать, то они должны быть выделены в виде типа. Способ работы заключается в последовательности шагов, которые выполняются соответствующим образом:
Решаемая здесь проблема заключается в том, что обычные программисты, например, с опытом работы на C / C ++, привыкли делать все это независимо. Это часто приводит к утечкам памяти, когда выделенная память больше не освобождается.
Однако эти методы могут вызвать другие проблемы. Иногда программисты используют память после ее освобождения, что может легко привести к ошибкам при повреждении памяти и даже проблемам с безопасностью. Учитывая, что мы избегаем небезопасного кода, приложение практически гарантированно защищено от повреждения памяти.
Идея управляемой кучи заключается не только в устранении этих ошибок, но и в том, чтобы предоставить значительно упрощенную модель программирования, которая включает только следующие шаги:
Другими словами, нет способа или необходимости наводить порядок. Тем не менее, это не означает, что нам никогда не придется наводить порядок самим. В определенных случаях, если мы используем типы, которые нуждаются в специальной очистке, мы можем выполнить очистку как можно скорее, не дожидаясь сборщика мусора. Все, что нам нужно сделать в этом случае, это вызвать специальный метод, например, dispose . Однако, как уже говорилось, это скорее редкий сценарий, чем норма.
Да, в .NET есть другой механизм повышения производительности, учитывающий размер объектов. Для больших объектов, т. Е. 85 000 байт или больше, среда CLR использует другую обработку:
Существует два режима сборки мусора (GC), которые использует среда CLR:
Режим рабочей станции настраивается исключительно для приложений, что больше подходит для клиентского режима. Поскольку он ориентирован на приложения, он обеспечит минимальную задержку для потоков приложений.
В режиме сервера сборка мусора оптимизируется для обеспечения большей пропускной способности и более эффективного использования доступных ресурсов. При сборке данных предполагается, что на компьютере не выполняются другие приложения.
Это также включает разделение GC между процессорами, чтобы на каждый процессор приходилось по одному разделу GC. Более конкретно, на каждый процессор приходится один поток, и поток собирает один раздел.
Это интересно, потому что включает в себя передовые концепции взаимодействия Microsoft Windows и COM (компонентная объектная модель) на фундаментальном уровне. Прежде чем обсуждать CLR-хостинг, мы должны изучить, как Microsoft выполняет .Среда выполнения NET в Microsoft Windows.
Поскольку .NET Framework работает в Windows, он будет реализован по тем же правилам. По умолчанию CLR была создана как COM-сервер, размещенный внутри библиотеки DLL. Это означает, что стандартный интерфейс идентифицируется с помощью присвоенных ему уникальных строк, называемых GUID (глобально уникальные идентификаторы).
Как правило, это было бы создано в COM с использованием вызова функции Windows с именем CoCreateInstance. Однако для CLR это работает так, что необходимо вызывать другую функцию вместо CLRCreateInstance , которая объявлена в заголовочном файле Metahost.h. Теперь эта функция реализована в библиотеке DLL под названием shim. Задача shim (MSCorEE.dll) – определить фактическую версию среды CLR, которую нужно создать. Однако в нем нет COM-сервера CLR.
Всякий раз, когда запускается управляемый исполняемый файл, оболочка проверяет его, чтобы понять, для какой версии CLR он был собран и протестирован. Может существовать несколько установленных версий CLR.
Чтобы разместить CLR, нам просто нужно использовать CLRCreateInstance, а затем запустить любое управляемое приложение, вызвав:
AppDomain.CurrentDomain.ExecuteAssembly(assemblyName);
Хостинг CLR может быть полезен, поскольку он позволяет любому приложению предлагать эти функции и может быть написан, по крайней мере частично, на управляемом коде. Некоторые из преимуществ включают:
Есть две основные причины использования потоков:
Мы также хотели бы отметить, что, хотя Microsoft изначально пыталась создать поток, отличный от Windows threads, для среды CLR, от этой идеи отказались после 2005 года. Они идентичны, но некоторые устаревшие API могут находиться внутри фреймворка.
Создание и уничтожение потока может быть трудоемкой операцией с точки зрения времени и памяти. Это также может повлиять на производительность системы, поскольку ОС должна переключать контекст между потоками.
CLR была разработана, чтобы помочь улучшить эту ситуацию, выполняя управление пулом потоков для своего собственного управляемого кода.
Итак, это работает, потому что у каждой среды CLR есть один общий пул потоков. В случае загрузки нескольких сред CLR в рамках одного процесса у каждой среды CLR есть отдельный пул.
Доступны три шаблона для выполнения асинхронных операций, а именно асинхронный шаблон на основе задач (TAP), асинхронный шаблон на основе событий (EAP), и модель асинхронного программирования (APM).
Последняя версия – .NET 9, преемница .NET 8. Эта конкретная версия ориентирована на облачные приложения и повышение производительности. Она включает в себя сильные основы облачных приложений, включая производительность во время выполнения и мониторинг приложений.
В предыдущем выпуске, .NET 8, акцент на ИИ уже был расширен за пределы ML.NET на TensorPrimitives для .NET, в дополнение к подключению к ChatGPT и Enterprise date с Azure OpenAI и когнитивный поиск .NET.