C#高级编程学习笔记(三)

61.异步编程
async 和await 关键字
在后台运行,通常在线程或任务的帮助下,并不会阻塞调用线程。
3种模式:异步模式,基于事件的异步模式,基于任务的异步模式。

62.进程与线程
程序在启动时,系统会在内存中创建一个进程。进程是程序运行所需资源的集合,这些资源包括虚地址空间、文件句柄和其他程序运行所需的东西。在进程的内部,系统创建一个称为线程的内核对象,代表真正执行的程序。当线程被建立时,系统在Main方法的第一行语句处开始执行线程。关于线程: 
默认情况下,一个进程只包含一个线程,从程序开始执行到结束;
线程可以派生其他线程,因此一个进程可能包含多个不同状态的线程,执行程序的不同部分;
一个进程如果包含多个线程,这些线程共享进程的资源;
系统中处理器执行的规划单元是线程,不是进程。 

63.同步与异步
同步是指从语句出现的先后顺序执行直到完成。
异步指语句并不严格按照出现的顺序执行。有时需要在一个新的线程中运行一部分代码,有时无需创建新的线程,为了提高单个线程的效率,改变代码的执行顺序。 
当某个操作需要花费大量的时间进行处理,若是使用同步编程,那么程序在等待响应的时间内不能处理其他事物,这样效率比较低;而使用异步编程时,在进行等待相应的时间内,程序可以利用等待的时间处理其他事物,当得到响应时,再回到响应处继续执行,这样程序的效率会更高。

64.async/await 特性
例子:源地址 https://www.cnblogs.com/WZH75171992/p/6093638.html 
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("主线程测试开始..");
        AsyncMethod();
        Thread.Sleep(1000);
        Console.WriteLine("主线程测试结束..");
        Console.ReadLine();
    }
 
    static async void AsyncMethod()
    {
        Console.WriteLine("开始异步代码");
        var result = await MyMethod();
        Console.WriteLine("异步代码执行完毕");
    }
 
    static async Task MyMethod()
    {
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine("异步执行" + i.ToString() + "..");
            await Task.Delay(1000); //模拟耗时操作
        }
        return 0;
    }
}
这个例子让我懂了 async/await的用法。

65.Task 
Task是在.NET Framework4中添加进来的,这是新的namespace:System.Threading.Tasks;它强调的是adding parallelism and concurrency to applications。
现在都是多核的CPU,在系统内,Task Parallel Library能更有效地利用CPU核心。TPL 会动态地按比例调节并发程度,以便最有效地使用所有可用的处理器。TPL 还处理工作分区、ThreadPool 上的线程调度、取消支持、状态管理以及其他低级别的细节操作。对比ThreadPool上的Thread并没有很好地支持Cancel的操作。
在语法上,和lambda表达式更好地结合。
https://blog.csdn.net/whereismatrix/article/details/77481808 参考博客

66.异步模式
异步模式定义了BeginXXX方法和EndXXX方法。如果有一个同步方法DownloadString,其异步版本就是BeginDownloadString和EndDownloadString方法。BeginXXX方法接受其同步方法的所有输入参数。

67.基于事件的异步模式
OnAsyncEventPattern方法使用了基于事件的异步模式,这个模式由WebClient实现。

68.基于任务的异步模式
(TAP)模式定义了一个带有“Async”后缀的方法,并返回一个Task类型。新方法名为DownloadStringTaskAsync 使用Await关键字会解除线程(这里是UI线程)的阻塞,完成其他任务。当方法完成其后台处理后,ui线程就可以继续,从后台线程中获得结果,赋值给字符串变量resp。然后执行await关键字后面的代码。

async 关键字创建了一个状态机,类似于yield return语句。

69.内存管理
运行库负责为程序员处理大部分内存管理工作。
关于运行库做了什么参考:https://www.cnblogs.com/widget90/p/5588081.html

70.后台内存管理
c#的一个优点是程序员不需要担心具体的内存管理,垃圾回收器会自动处理
所有的内存清理工作。
Windows使用一个虚拟寻址系统,把程序可用的内存地址映射到硬件内存中的实际地址上,这些任务完全由Windows在后台管理。4GB的内存称为虚拟地址空间,每个存储单元都是从0开始往上排序的。在C#中,编译器负责把人们可以理解的变量名转换成处理器可以理解的内存地址。在释放变量时,其顺序总是与给它们分配内存的顺序相反,这就是栈的工作方式。

71.引用数据类型--托管堆来管理
托管堆是处理器上可用4GB中的另一个内存区域。只要保持对数据的引用,改数据就肯定存在于堆上。我们可以对数据的生存期进行非常强大的控制。

72.垃圾回收
在垃圾回收器运行时,它会从堆中删除不再引用的所有对象。在完成删除操作后,堆会立即把对象分散开来,与已经释放的内存混合在一起。

73.托管的堆
使用托管的堆,就只需要读取堆指针的值即可,而不需要遍历地址的链表,来查找一个地方来放置新数据。

74.垃圾回收的平衡也有助于提高应用程序性能,它专用于服务器的垃圾回收,服务器一般有一个线程池,执行大致相同的工作。

75.释放非托管的资源
在定义一个类时,有两种机制来自动释放非托管的资源。
1.声明一个析构函数(或终结器),作为类的一个成员
2.在类中实现System.IDisposable接口。

76.析构函数 
一、C#析构函数
  析构函数的定义与注意的问题
析构函数用于释放被占用的系统资源。
析构函数的名字由符号“~”加类名组成。
使用析构函数时,应该注意下面的问题:
1.只能在类中使用析构函数,不能在结构中使用析构函数。
2.一个类只能有一个析构函数。
3.不能继承或重载析构函数。
4.析构函数只能被自动调用。
5.析构函数没有任何修饰符、没有任何参数、也不返回任何值。

  调用析构函数
1.垃圾回收器决定了析构函数的调用,我们无法控制何时调用析构函数。
2.垃圾回收器检查是否存在应用程序不再使用的对象。如果垃圾回收器认为某个对象符合析构,则调用析构函数(如果有)并回收用来存储此对象的内存。
3.程序退出时会调用析构函数。
4.我们可以通过调用Collect强制进行垃圾回收,但是请不要这样做,因为这样做可能导致性能问题。

二、构造函数与析构函数的区别
1.构造函数和析构函数是在类中说明的两种特殊的成员函数。
2.构造函数是在创建对象时,使用给定的值将对象初始化。
3.析构函数用于释放一个对象。在对象删除前,使用析构函数做一些清理工作,它与构造函数的功能正好相反。

77.用指针直接访问内存
引用就是一个类型安全的指针,指针只是一个以与引用相同的方式存储地址的变量。向后兼容性和性能是使用指针的两个主要原因。
指针使用不当会导致栈溢出,访问某些没有存储变量的内存区域,甚至重写.NET运行库所需要的代码信息。

78.指针
指针实际上存储了一个表示地址的整数,指针到整数类型的转换必须是显式指定的。可以把一个指针强制转换为任何整数类型,把指针强制转换成非ULONG类型,可能导致溢出错误。
如果要维护一个指针,但不希望它指向的数据类型,就可以把指针声明为void
&表示“取地址”,并把一个值数据类型转换为指针
*表示“获取地址的内容”,把一个指针转换为值数据类型

79.sizeof运算符
需要在代码中使用某种类型的大小,就可以使用sizeof运算符,它的参数是数据类型的名称,返回该类型占用的字节数。

80.结构指针
结构指针不能包含任何引用类型,因为指针不能指向任何引用类型。

81.使用指针优化性能
在栈中创建高性能,低系统开销的数组。但指针只对于一维数组比较简单。
需要使用关键字stackalloc命令,提供要存储的数据类型和需要存储的数据项数。stackalloc总是返回分配数据类型的指针,它指向新分配内存块的顶部。

82.自定义特性
自定义特性允许把自定义元数据与程序元素关联起来,这些元数据是在编译过程中创建的,并嵌入到程序集中。
自定义特性详解:https://www.cnblogs.com/roucheng/p/cstexing.html

83.反射
发射描述了在运行过程中检查和处理程序元素的功能。
反射允许完成一下任务:
枚举类型的成员
实例化新对象
执行对象的成员
查找类型的信息
查找程序集的信息
检查应用于某种类型的自定义特性
创建和编译新程序集

反射的理论参考:https://www.cnblogs.com/Stephenchao/p/4481995.html
反射的实现参考:https://www.cnblogs.com/May-day/p/6639096.html

84.属性类需要指定:
特性可以应用到哪些类型的程序元素上(类,结构,属性,方法等)
它是否可以多次应用到同一个程序元素上
特性在应用到类或接口上时,是否由派生类和接口继承
这个特性有哪些必选和可选参数

85.system.Type类
通过这个类可以访问关于任何数据类型的信息,Type实际上是一个抽象的基类,只要实例化了一个Type对象,实际上就实例化了Type的一个派生类。
有3种常用方法获取指向的给定类型的Type
使用C#的typeof运算符
使用GetType(方法)
调用Type类的静态方法G儿童Type()

Type是许多反射功能的入口,它实现许多方法和属性

86.Assembly类
在system.Reflecttion名称空间中定义,它允许访问给定程序集的元数据,它也包含可以加载和执行程序集的方法。

你可能感兴趣的:(学习笔记)