.Net 新一代编译器 Roslyn 会带来怎样的影响?
.Net 新一代编译器 Roslyn 会带来怎样的影响?
Roslyn是微软创建的一个.NET编译器平台,该项目于2014年4月3日开源。
最初 C# 语言的编译器是用 C++ 编写的,后来微软推出了一个新的用 C# 自身编写的编译器:Roslyn,它属于自举编译器。
.NET Compiler Platform,也被称为Roslyn
该项目特别包括 C# 的自承载版本和 VB.NET 编译器(用语言本身编写的编译器)。编译器可通过传统的命令行程序获得,但也可作为 API 从 .NET 代码中本机获得。Roslyn 公开了用于代码的句法(词法)分析、语义分析、CIL 动态编译和代码发布等模块。[注3]
Roslyn最显着的主要特征包括:
C#代码编译器 Roslyn 附带的源生成器(Source Generators)。 源生成器是一项 C# 编译器功能。
1,NET Framework和.NET Core的结构体系
a.NET Framework 包含,Windows Form,WPF,ASP.NET
b.NET Core 包含,UWP,ASP.NET Core
c.Xamarin,新的.NET还包括第三个部分,即XAMARIN用于构建移动APP,包含iOS、 OS X 、Android等。
即所谓的.NET三架马车,下面是最新的.NET生态体系图:
2,.NET Core构成体系
上面说到.NET的三驾马车,.NET Framework、.NET Core、XAMARIN,下面主要看一下.NET Core的组成
如上图,NET Core 构成体系:
(1) Runtime 在.NET Core 中有实现两种RunTime,NativeRuntime 和 CoreCLR。NativeRuntime 将C# 或 VB.net 代码直接转换为原生机器码。而CoreCLR是一个开源的JIT运行时,会将代码编译成中间语言(IL)在最终运行时再转换机器码。
(2) Unified BCL Base Classlibrary即基础类,例如 FileSystem、Console、XML操作等。
(3) Windows Store AppModel & ASP.NET Core 1.0 提供开发Windows系统的各种触屏设备和ASP.NET程序的一组基础库。
3,.NET Core各个功能模块
如上图:
应用层: .NET Core的系统构成,最上层是应用层,是开发基于UI应用的框架集,包括了ASP.NET Core(用于创建web app),和 UWP(用于创建Windows10 app)。
中间层:中间层是公共库(CoreFX):实现了.NET Standard Library ,囊括了常用系统级操作例如(文件、网络等)。
在CoreFx下是运行时环境,.NET Core 包含了两种运行时(CoreCLR、CoreRT),CoreCLR是一种基于即时编译程序(Just in time compiler,JIT)的运行时,它使用了跨平台开源的编译器RyuJIT,
而CoreRT是使用提前编译器(Ahead of time compiler,AOT)的运行时,它既可以使用RyuJIT来实现AOT编译也可以使用其他的AOT编译器。由于AOT提前编译IL成了机器码,在移动设备上也具有更好的启动速度和节能性。
编译器:最后还要提到一个开源的跨平台源代码编译器Roslyn,它有别于刚才两个编译器,JIT和AOT编译器主要用于将IL编译成本机机器码,而Roslyn是将C# 或 VB.NET 代码编译成程序中间语言(intermediate language,IL)。
下面介绍这个编译器。
4、NET Core的Roslyn 编译器
Roslyn编译器用于将C#或VB.NET代码编译为程序集(assembly),它的编译过程是一个管道式的处理过程一共包含4个步骤,具体过程见下图。
A. Parser(解析)
根据语法对源代码进行解析。
B. Declaration (声明)
为代码生成元数据(metadata),元数据是一个数据表的集合,描述了在当前代码中定义的数据类型和成员,同时也描述了引用的类型及成员。
C. Bind(绑定)
将生成的IL代码与描述它的元数据绑定在一起,生成托管模块(managed module)。
D. Emit(生成)
将一个或多个托管模块合并生成程序集(assembly)。
(2)RyuJIT 编译器
在程序运行中需要执行某一个方法,首先需要将已经编译好的IL转换本机的机器码,而这个任务就交给了RyuJIT。它是新一代JIT编译器,第一次实现了AMD64的架构,RyuJIT能够比JIT64(上一代编译器)更快地生成代码,以提高程 序运行效率(测试详情链接)。
(3) CoreCLR & CoreRT
CoreCLR 和 CoreRT 都是.NET Core的运行时(Runtime),它们提供了与.NET Framework CLR 类似的核心功能(内存管理、程序集加载、安全性、异常、线程管理等),可由面向于运行时的所有语言使用。
CoreRT 和 CoreCLR 不同的是,CoreRT 提供了一套AOT 的机制,可以将.NET Core程序编译成原生代码,不依赖 .NET 运行时而运行在宿主机器上。
除此之外两个运行时大部分功能代码是共享的,比如GC。AOT的优化带来不少好处:
编译后生成一个单文件,包含所有的依赖,包括 CoreRT,无需安装Framework
启动时是机器码,不需要生成机器码,也不要加载JIT编译器
可以使用其他优化编译器,包括 LLILC ,IL to CPP
CoreRT有两个方式生成机器码,第一个使用是直接编译IL成机器码,默认情况下,RyuJIT 作为一个 AOT 编译器将IL编译成机器码,另一个方式是将C#代码编译成C++代码,然后调用对应平台的C++编译器优化编译成机器码。
使用 RyuJIT 编译成机器码
dotnet restore dotnet build --native --ilcpath <repo_root>\bin \Product\Windows_NT.x64.Debug\packaging\publish1
编译生成 C++ 代码
dotnet restore dotnet build --native --cpp --ilcpath <repo_root>\bin\Product\Windows_NT.x64.Debug\packaging\ publish1 --cppcompilerflags /MTd
CoreRT也有不足之处,它需要为不同平台编译一次;但凡事有但是,它允许工程师可以不发布到不想支持的平台(比如某游戏仅支持桌面,不支持手机)。
(4) CoreFX(.NET Core Libraries)
CoreFX主要包含数个公共库,例如 System.Collections, System.IO, System.Xml等。CoreFX是 .NET Standard Library 的实现,同样的.NET Framework 4.6.3也是基于.NET Standard Library的实现。它们目前都是基于.NET Standard Library1.6版本,具体见下表:
5、.NET Core 代码开发、部署、运行过程
从上图可以看到使用JIT编译和使用AOT编译源代码并运行程序是两种不同的流程。
如果使用JIT编译器部署程序时只需要将程序打包为IL的assemblies,在方法第一次执行前编译器将IL编译为目标机机器码(Native code),而AOT编译会在编译时将源代码直接编译为目标机机器码。
AOT将源代码编译为机器码,拥有如下特性:
(1)用静态代码替换反射,例如如果一个值类型(value type)没有重写 ValueType.Equals 的equals的方法,默认情况判断相等,会使用反射找到filedinfo以确定type是否相等,然后再比较value是否相等。而在AOT编译中由于替换了反射因此只能比较value是否相等。
(2)依赖的第三方类库以及.NET Libraries均打包至最终编译的程序中。
(3)打包后的程序运行在一个精简版的运行时上(CoreRT)主要包含垃圾回收器,而运行时也会打包在app文件中。
(4)虽然编译时会替换反射代码,但遇动态反射代码无能为力,运行时若遇动态反射调用则会因找不到对应的元数据及实现而抛出异常。解决办法是编译前配置运行时指令文件(Runtime directive file)指定需要用到的程序集。
6,总结
主要介绍了.NET的三驾马车.NET Framework、.NET Core、Xamarin,.NET Framework是开发基于Windows平台的王者框架,而.NET Core的跨平台特性、开源及灵活的部署机制将是.NET的未来。后面介绍了.NET Core的组成、.NET Core主要功能模块:应用层、中间层、编译器。最后简要介绍了.NET Core的开发、部署、运行流程。