本文要点:
Mono 项目始于 2001 年,是首个面向.NET 应用程序的多平台、开源框架的项目。Xamarin 和 Blazor 分别代表了微软在移动和 Web 应用程序方面的努力,它们都是基于 Mono 并由 Mono 提供支持的。.NET 5 为用户提供了两种运行时选项:高性能的 CoreCLR(用于服务器和桌面应用程序)和轻量级的 Mono(用于移动设备和 WebAssembly)。尽管 Mono 已经是.NET 的一部分了,但仍有一些开发工作要致力于改善 Mono 的运行时性能和垃圾回收器。现在.NET Core 可以与 Mono 并行安装了,因此可以一起演进语言和运行时。
去年,微软发布了它的计划,其中涉及.NET 未来以及.NET 5 的路线图。计划于今年年底发布下一个主要版本,该版本旨在提供一个基于.NET Core、.NET Framework、Xamarin 及 Mono 最佳部分的多平台、开源框架和运行时。
微软从 2014 年开始向.NET 开源发展,当时微软宣布.NET Core 即将开源。然而,在此之前,.NET 就已经有了一个名为 Mono 的开源计划。 Mono 项目始于 2001 年,最初它主要致力于为 Linux 桌面应用程序建立一个.NET 开发平台。第一次正式版本是在 2003 年发布的,此后该项目逐渐演进为在多个平台和操作系统上支持.NET。
Mono 是由 Xamarin 从 2011 年开始开发的。自从该公司被微软收购,并在 2016 年发布.NET Core 1.0 以来,Mono 和.NET Core 一直在并行开发。根据最新发布的版本,InfoQ 采访了 Miguel de Icaza(目前他就职于微软,是 Xamarin 的联合创始人,Mono 项目的原作者),讨论了 Mono 的现状及其在.NET 生态系统中的未来,以及 Xamarin 如何适合这种情况。
InfoQ:从技术上讲,.NET Core 和 Mono 之间的主要区别是什么?
Miguel de Icaza:Mono 是基于.NET Framework 的,.NET Framework 是作为 Windows 一部分发布的.NET 大版本。经过多年的发展,Mono 和.NET 都可以应用在不同的环境中。在.NET 领域中,这最终导致了.NET Core 3(这是所有未来工作和创新的基础)的发布,而.NET Framework 是一个长期维护的版本,它将继续被修复和调整。 但不会有任何重大的创新。
在 Mono 的世界里,运行时演进为支持我们所谓的“移动配置文件”,它是 API 的一个精选子集,适用于平衡用户需求与降低独立运行时部署的需求。这是 Xamarin .NET 努力的基础,也是最近 WebAssembly 工作的基础。
使用.NET 的不同场景以及使用它们的环境将开发人员必须使用的 API 集合分割开了。对于开发人员来说,没有一种简单的方法可以发布在所有平台上都可以工作的库二进制文件。
创建能够适用于所有不同环境的二进制库的愿望是创建.NET 标准的推动力——一个 API 的通用界面,可以在所有不同版本的.NET 上工作,无论是小型设备、移动系统,还是大型服务器。我们在这里所采取的方法是提出一套在所有平台上都可以平等使用的 API。但这仍然意味着我们要维护库的不同实现。
让.NET 的所有变体都能够相互操作的方法就是.NET Standard,.NET Standard 的每个新版本中都添加了更多的 API,所有运行时都能确保这些 API 是通用的。当今使用最广泛的 API 契约是 .NET Standard 2, .NET Framework、.NET Core、Xamarin 和 Mono 都支持该标准。
新的.NET Standard 2.1 版本引入了新的创新功能,但它们仅在 Mono、.NET Core 和 Xamarin 上可用,这是首个不被长期受支持的.NET Framework 所支持的.NET Standard 版本。
InfoQ:考虑到.NET Core 的最新成果以及.NET 5 的路线图,Mono 在当前状态的.NET 生态系统中地位如何?
de Icaza:简短的版本是,随着即将到来的.NET 5,用户将能够在所有平台上使用相同的 API 集合,并且可以选择运行时(CoreCLR 或 Mono)和编译系统(静态编译、JIT 编译、分层或解释)来解决其问题的特定需求。
使用.NET 5,我们统一了类库的实现,同时为用户提供了两种运行时选项。在较高的层次上,在 CoreCLR 中具有一个高吞吐量、高性能的运行时,还具有一个轻量级(但速度没有那么快)的 Mono 运行时。每个运行时都已针对它们最常使用的工作负载进行了调整:CoreCLR 用于服务器和桌面应用程序;Mono 用于移动和轻量级应用程序,例如 WebAssembly。
同样在.NET 5 中,我们将有一个统一的运行时,它可以在我们支持的所有平台上执行 C#或 F#代码。在某些平台上,用户将能够选择他们想要使用的运行时,而在其他平台上,将只有一个运行时可以使用。例如,对于 Windows 上的桌面应用程序,只有 CoreCLR 运行时适用,而对于 iOS,只有 Mono 运行时可用。
现在,从历史上看,Mono 具有两种执行和代码生成引擎。一种是我们称之为“mini”的代码生成器,它可以非常快速地生成本地代码,但是没有进行很多优化。为了实现更好的优化,Mono 过去一直都依赖 LLVM 优化编译器。 LLVM 以牺牲编译时间为代价,产生漂亮的、最优的、完善的代码。
此外,Mono 具有两种操作模式:一种是运行时在执行时动态生成代码(我们称之为 JIT 编译),另一种是运行时提前编译代码(基本上是静态编译)。提前(AOT)编译系统用于不允许动态代码生成的平台(例如 iOS 或视频游戏机),或者必须提高启动性能的平台(低端手机上的某些 Android 应用)。
Mono 可以在纯 JIT、混合 AOT/JIT 或 AOT 模式下运行,具体取决于平台的要求或用户的需求。因此,通常会使用 LLVM 提前编译一些核心库,例如,在保留用户代码可以动态编译 (JIT) 的情况下,为这些库生成最佳的代码。
需要纯 AOT 的系统有一个缺点,那就是.NET 的动态功能不可用(例如,动态实例化类型、使用 C# dynamic 关键字、或动态加载代码等)。因此,我们着手解决这个问题。
去年,我们在 Mono 中引入了一个新的执行引擎和模式——一个解释器。事实证明,该解释器非常有用,这不仅是因为它能够带来动态性(以前缺少动态性),允许我们将一个小的运行时部署到 WebAssembly,而且还能够使我们为用户带来一些“Hot”之类的功能,比如热加载和热重启。
一旦我们拥有三个具有不同配置的引擎,就有必要带来一个分层编译系统,该系统允许 Mono 运行时根据代码的使用方式动态调整要使用的代码生成引擎。并使用启动时间、内存使用率和长期性能。这是一个活跃的研究领域,我们也希望能够在该领域调整参数、学习或向用户提供解决方案。
.NET 5 的好处在于,.NET 5 的所有功能都可以在所有平台上使用,用户无需调整或更改任何内容。开箱即用的体验已经配置为全面匹配最佳可能的配置。
InfoQ:Xamarin 和 Blazor 有什么区别?
de Icaza:Xamarin 是我的初创公司,专注于帮助.NET 开发人员实现移动化。我们使用 Xamarin 作为一系列产品的品牌,从开发工具到在线服务都使用该品牌。到目前为止,在线服务已被整合到 Azure DevOps 中了。
Xamarin 开发工具包括原生 SDK 和 Xamarin.Forms。原生 SDK 允许开发人员瞄准 Android 和 iOS,并使用.NET 平台中的所有原生功能。 Xamarin.Forms 是一个跨平台的 UI 工具包,它使开发人员可以一次定义其用户界面,并将相同的代码映射成目标减肥平台的本机习惯用法。Blazor 是一种通过 C#构建交互式 Web 应用程序的新方法,它将一些最易于使用和最受欢迎的 Web 开发模式引入到了.NET。
开发人员可以构建 Blazor 应用程序,并可以选择逻辑运行的位置,它可以运行在由 ASP.NET 提供支持的服务器上,也可以完全运行在客户端上(为此,我们使用 WebAssembly 在浏览器内部运行一个.NET 运行时)。值得注意的是,在 WebAssembly 上支持.NET 的工作,当时是由 Xamarin 的 Mono 团队完成的,但是编程模型完全是由 Blazor on WebAssembly 开发团队构思出来的。 Mono 只是提供了执行它们代码的方法。
InfoQ:是否可以将 Mono 与其他微软的.NET IDE(Visual Studio、VS Code 等)一起使用呢?
de Icaza:当然可以。尽管大多数问题都是在展望.NET 5 的未来,但是现在,在移动设备、Xamarin 上构建支持.NET 的应用程序,或构建针对 WebAssembly 的 Blazor 应用程序,Mono 都是它们的引擎。这些功能在 Visual Studio 和 Visual Studio Code 也是开箱即用的。
除了微软官方支持的配置之外,Mono(作为一个开源项目)仍然支持“ .NET Framework”兼容模式,并且可以与 Mac 上的 Visual Studio 或 Linux 上的 MonoDevelop 一起使用,以构建.NET Framework 应用程序。 这的确是我业余时间做的一些工作,比如 TensorFlowSharp、TorchSharp(PyTorch for .NET 的绑定)和 gui.cs(一个用户界面系统,可用于使用.NET 构建文本用户界面)。
InfoQ:还有一些其他与.NET Core 相关的框架,比如 EF Core、ASP.NET Core 等。这些框架是否与 Mono 兼容呢?
de Icaza:使用.NET 5,它们都是受支持的。在.NET 5 之前,像 ASP.NET Core 之类的东西无法与 Mono 一起使用,这主要受限于与它相关的工具,而不是受限于运行时。
例如,EF Core 是面向移动应用程序用户最喜欢的工具,它利用了.NET Standard,可以在 Mono 上开箱即用。
InfoQ:.NET 生态系统中,Mono 的未来是什么?
de Icaza:现在,它已经从独立工作中毕业,逐步发展成为了整个.NET 的一部分。现在.NET 将会有一个单一发行版,该发行版会针对我们多年来积累的每个平台。我对开源社区多年来的支持工作感到非常自豪,也对我们团队持续集成这些 VM 的工作感到自豪。
现在出现了一些引人入胜的发展。例如,就在今天,在使用本地配置运行 TechEmpower 基准测试时,我看到使用静态编译和 LLVM 的 Mono,现在可以与 CoreCLR 的性能相匹配了。
这对于 Mono 来说是一个重要的里程碑,因为当我们开始这项工作时,Mono 离我们的目标还很远,甚至不在同一个球场上。但是,我们开始研究是什么导致了 Mono 的性能下降,分析并测量,直到我们找到了大多数的罪魁祸首,然后我们才到达这个位置。
Mono 历来都有一个精确的垃圾回收器,该垃圾回收器轻量、高效, 适用于移动设备,但是对于这些拥有许多 CPU 和大型内存子系统的新计算机而言,它的扩展性却不佳。因此,我们现在有了一个使用 CoreCLR GC 的 Mono 的原型,这是一个针对 Mono 本身可高度扩展的 GC。我希望我们将来能够为用户提供 GC 选项。
除此之外,世界看起来越来越像一个统一的 VM,开箱即用地支持 C#和 F#,这是摆在我们面前最令人兴奋的工作。
到目前为止,将我们的语言和运行时一起演进是很困难的,因为演进运行时需要演进世界上每台 Windows 计算机上附带的运行时。为了避免回归共享框架(由许多用户共享),许多风险缓解流程已经就位,并且这些流程阻止了一体化进程中的大胆变革。
现在 .NET Core 可以并行安装了,并且可以按照用户需要的频率进行升级,我们有了千载难逢的机会来共同演进语言和运行时,而且你已经可以看到其中的一些东西了。一些功能,例如接口中的默认方法实现,以及对整个类库进行改造以使其可为空引用,这是最近的一些开发,但是还有更多的功能有待开发,因此还会有很多机会将被解锁。