.net运行环境串讲

一、程序集和元数据:(元数据就是程序集的描述性语言)

程序集构成了.NET应用程序的部署、版本控制、重用、激活范围和安全权限的基本单元,是为协同工作而生成的类型和资源的集合,这些类型和资源构成了一个逻辑功能单元。

程序集具有以下属性:

      程序集以 .exe 或 .dll 文件的形式实现 。

      对于面向 .NET Framework 的库,可以通过将程序集放入全局程序集缓存 (GAC),在应用程序之间共享程序集。 必须先对程序集进行强命名,然后才能将它们包含到 GAC 中。 

      只有在需要使用时才会将程序集加载到内存中。 如果未使用程序集,则不加载。 也就是说,使用程序集,可以在大型项目中高效管理资源。

      可以使用反射,以编程方式获取程序集的相关信息。

      你可以加载一个程序集,以使用 .NET Core 中的 MetadataLoadContext 类以及 .NET Core 和 .NET Framework 中的 Assembly.ReflectionOnlyLoad 或 Assembly.ReflectionOnlyLoadFrom 方法来检查该程序集。

程序集的创建过程:

程序集的组成:

    IL code:中间代码(MSIL),编译器产生的面向CLR的代码,在运行时CLR利用JIT即时编译器将其转换为本地CPU指令。

    Metadata:  元数据是以二进制数据组成的块(a block of binary data),包含三类表:定义表(definition tables)、引用表(reference tables)、清单表(manifest tables)。

        定义表(definition tables): 包含本模块内定义的类型,方法,字段,参数,属性,事件。

      引用表(reference tables): 包含了本模块所引用的数据集,模块,类型,方法,字段,属性,事件。

   清单表manifest tables):  是描述整个程序集的表,它包含了程序集中所有文件的名称以及程序集的版本、文化、出版者、公开导出的类型。

    PE32/PE32+ header :标准windows PE(可迁移可执行)头文件,主要指定了该模块是32还是64位文件,还指定了该模块是GUI(exe),CUI(exe)或者DLL 其中的一种。

    CLR header:CLR header 的定义在CorHdr.h文件中,它主要包含CLR版本、模块入口函数(Main函数)的MethodDef元数据、元数据的大小及偏移量、可选的强签名。

元数据是一种二进制信息,用以对存储在公共语言运行时可迁移可执行文件(PE)文件或存储在内存中的程序进行描述,将您的代码编译为PE文件时,便会将元数据插入到该文件的一部分中,而将代码转换为Microsoft中间语言(MSIL)将其插入到该文件的另一部分中,在模块或程序集中定义和引用的每个类型和成员都将在元数据中进行说明, 当执行代码时,CLR运行时将元数据加载到内存中,并引用它来发现有关代码的类、成员、继承等信息。

元数据存储以下信息:

  程序集的说明

    标识(名称、版本、区域性、公钥)

    导出的类型

    该程序集所依赖的其他程序集

    运行所需的安全权限

  类型的说明

    名称、可见性、基类和实现的接口

    成员(方法、字段、属性、事件、嵌套的类型)

  特性

    修饰类型和成员的其他说明性元素

元数据具有以下主要优点:

  自描述文件

    公共语言运行时模块和程序集是自描述的,模块的元数据包含与另一个模块进行交互所需的全部信息,元数据自动提供COM中IDL的功能,因此可以将一个文件同时用于定义和实现,运行时模块和程序集甚至不需要向操作系统注册,

    运行时使用的说明始终反映编译文件中的实际代码,从而提高应用程序的可靠性。

  语言互用性和更简单的基于组件的设计

    元数据提供所有必需的有关已编译代码的信息,以供你从用不同语言编写的PE文件中继承类,你可以创建用任何托管语言(任何面向公共语言运行时的语言)编写的任何类的实例,而不用担心显式封送处理或使用自定义的互用代码。

  特性
    .NET 允许在编译文件中声明特定种类的元数据(称为特性)。特性在.NET中处处可见,用于更精确地控制程序在运行时的行为,另外还可以通过用户定义的自定义特性,向.NET文件发出自己的自定义元数据。

元数据的作用:

       1、在微软没有推出元数据技术的时候,出现的一个问题是,二进制代码复用非常的麻烦,当时的二进制的复用是通过com组件技术实现的,即我们编写一个com组件,然后编译好的内容给别人使用,别人不能很好的使用,为什么呢?

       因为别人再调用你的com组件的内容时是硬编码,硬编码就是没有智能提示,调用的方法不知道是不是com组件中的方法,不知道写错了没有,要想知道必须运行才能知道。所以元数据主要作用就是解决二进制代码的复用。

    2、元数据可以被VS集成开发环境直接使用,而且是非常的普遍,如:我们添加一个程序集的引用,就可以直接非常方便的使用,其根本就是使用了程序集元数据的缘故,

       其实元数据也是可以被我们编程人员使用,其使用的一种方式就是反射,反射的技术就是使用元数据达到的,我们通过反射的技术可以获得程序集的信息、类的信息和类内部的信息,可以创建一个对象,可以调用方法等等。

       3、除了系统帮助我们生成一些元数据外,我们在编程的时候也可以自己给类、方法、属性等添加一些元数据,这就是特性的产生,特性是更高层次上的抽象。

二、公共语言运行时(CLR)

.NET 提供了一个称为公共语言运行时的运行时环境,它运行代码并提供使开发过程更轻松的服务。公共语言运行时的功能通过编译器和工具公开,你可以编写利用此托管执行环境的代码。使用面向运行时的语言编译器开发的代码称为托管代码,托管代码具有许多优点例如:跨语言集成、跨语言异常处理、增强的安全性、版本控制和部署支持、简化的组件交互模型、调试和分析服务、线程池调度服务、垃圾回收GC服务等。若要使公共语言运行时能够向托管代码提供服务,语言编译器必须生成一些元数据来描述代码中的类型、成员和引用。

托管的执行过程包括以下步骤:

  选择编译器

    若要获取公共语言运行时提供的好处,必须使用一个或多个面向运行时的语言编译器。

  将代码编译为MSIL

    编译将你的源代码转换为Microsoft中间语言 (MSIL) 并生成必需的元数据。

  将MSIL编译为本机代码。

    在执行时,实时(JIT)编译器将MSIL转换为本机代码,在此编译期间,代码必须通过检查MSIL和元数据的验证过程以查明是否可以将代码确定为类型安全。

  运行代码

    公共语言运行时提供启用要发生的执行的基础结构以及执行期间可使用的服务。

三、多线程技术

这里很多同学可能对于多线程编程涉及的关键词同步、异步、并发、并行概念有点混淆,总之我们理解的话还是需要从CLR中的线程池和多核心CPU作为切入点。

并发:

并发是多线程技术可以解决的问题,利用CLR提供的线程池ThreadPool,可以很好的均衡线程创建和销毁对CPU的消耗,例如我们在服务端编程时,端口监听到链接后可以利用负载均衡技术将它分发到多个线程中。

并行:

并行编程也是基于多线程技术的,但它强调的是高效完成计算任务而不是并发数量,着重加强了对CPU的利用率,因为现在随着硬件的发展很多cpu都是多核多线程的,所以直接利用CLR的线程池编写的并行程序并没有利用到cpu多核多线程带来的高效率,所以.net提供了异步任务(Task)的技术来进行并行开发,可行充分的利用cpu的多核多线程,当然还有其它并行技术,但是官方推荐的还是使用Task(性能高、效率高、可控性强)。

同步:

这里的线程同步其实指的是多线程编程中线程同步阻塞I/O的问题,对于多线程共享的模块,为了线程安全可以使用线程同步锁(Lock)的机制,当然还有其它同步机制,但是官方推荐Lock。

异步:

为了解决长时间的任务对UI线程阻塞I/O的问题我们用异步编程解决(主要是Task结合asyc、awit的用法,这里可以满足多核cpu),GUI线程是有安全机制的不允许跨线程直接访问,同时它是前台主线程,如果前台线程阻塞超过一定时间就会锁住界面,所以不适合处理长时间的任务,这时异步编程就排上用场了,然后使用.net提供的Invoke和Dispatcher来访问刷新UI线程。

PS: 

       CPU组成:控制单元(指令集)、存储单元、运算单元。

       IO:文件IO、网络IO、线程阻塞IO。

原文地址:https://www.cnblogs.com/happyShare/p/14005138.html