首页 > 编程语言 >C#进阶

C#进阶

时间:2022-10-23 11:44:05浏览次数:65  
标签:异步 Task 进阶 C# await 线程 方法 Socket

未完成,不定时更新

一、进程与线程

平时写简单程序的时候都是单线程,编译器只给程序分配一个主线程。
但是后续随着难度增加,程序功能的复杂,主线程一拳难敌四手,容易造成程序假死。
于是我们需要创建线程,来执行程序的部分功能。

1.1 前台线程与后台线程

前台线程:

由 Thread 类创建的线程默认是前台线程。所有前台线程关闭后,程序才能关闭。

后台线程:

只要所有前台线程结束,后台线程自动强制结束。

1.2 线程定义

Thread th = new Thread(方法名);//线程定义
th.IsBackground = true;		//设置为后台线程(默认为前台线程)
th.Start();					//线程待命(方法如果是带参数的,在start里面填参数
							//	而且必须是object类型)

详细的属性、方法查看MSDN、此样例属于第二构造函数

1.3 处理线程间异常

//程序加载时加上:
Control.CheckForIllegalCrossThreadCalls = false;

二、Socket编程

2.1 概念入门

2.1.1 Socket

类似两个人打电话

程序通过 Socket 通信
人通过 电话 通信

电脑与电脑联系需要规定 协议
人与人联系需要规定 语言

服务器:负责监听的 Socket,负责跟客户端进行通信的Socket。
客户端:负责跟服务器进行通信的Socket。

2.1.2 同步、异步、阻塞、非阻塞

术语 解释
同步 Client发送请求后,只有得到Server回应才可以发下一个
异步 Client发送请求后,无需等待回应即可发送下一个请求
阻塞 执行socket的调用函数只有得到结果后才返回,否则当前thread将挂起,此socket一直阻塞在线程调用上
非阻塞 执行socket调用函数时,无论是否受到结果,立即返回,不会阻塞thread

2.2 C/S通信流程

在这里插入图片描述

2.3 Socket的两种类型

2.3.1 流式Socket (STREAM):

一种面向连接的Socket,针对TCP服务应用,安全,效率低。

2.3.2 数据报式Socket (DATAGRAM):

一种无连接的Socket,针对无连接的UDP服务应用,顺序混乱,在接收端要分析重排及要求重发,但是效率高。

2.4 Socket例子

网上有很多例子,可自主查找或访问MSDN。
TCP案例1
TCP案例2
UDP案例

三、多线程与异步编程

3.1 异步引入背景

启动程序时,系统会在内存中创建一个新的进程 (Process),进程是构建运行程序的资源集合。在进程的内部系统创建了一个称为线程 (Thread) 的内核对象,它代表了真正执行的线程,系统会在Main方法的第一行开始线程执行。

  • 默认情况下一个进程仅包含一个线程(主线程);
  • 线程可以派生其他线程;
  • 如果一个进程拥有多个线程,它们将共享进程资源;
  • CPU执行调度的单元是线程;

如果程序都同步单线程的运行,那么在一些C/S多对多通讯上、GUI交互上会出现“卡死”,“等待”等一些弊端。因此引入了异步,使得程序代码不必按照顺序严格执行。

3.2 async/await 特性异步

C#5.0 引入了这个特性,方便实现异步。
async是上下文关键字,代表下文提到的await将作为异步方法,而非函数名称。

3.2.1 结构

该特性由3部分组成:

  • async 异步方法
  • await 表达式
  • 调用方法
class Program
{
	static void Main()
	{
		...
		Task<int> value = AsyncClass.XXXAsync(X,X);	//调用异步方法
		...	
	}
}

static class AsyncClass
{
	public static async Task<int> XXXAsync(X,X)	//async 异步方法
	{
		int sum = await 调用其他方法;		//await 表达式
		return sum;
	}
}

当Main调用异步方法时,方法将立即返回一个Task类型的占位符对象,然后才开始执行异步方法。此时由于已经返回,主线程不会阻塞,将会继续执行。当异步方法执行完毕后,会返回一个int给占位符。

3.2.2 返回值类型

共有4种:

  • Task:不需要返回某个值,但是需要检查异步方法的状态,返回一个Task类型对象即可;
  • Task<T>:调用方法将通过Task的Result属性来获得这个T类型的值;
  • void:仅仅想用异步;
  • ValueTask<T>:这是一个值类型对象

虽然异步方法的返回值如上,但是方法体中不包含任何返回如上类型的return语句。
这与异步控制流有关:
到达await时出现2个流:1、异步方法内;2、调用方法内

  1. 异步方法内
    • 异步执行await空闲任务;
    • await完成后,执行后续部分;
    • 遇到return、末尾时:
      1. 返回类型void:控制流退出
      2. 返回类型Task;设置Task状态属性后退出
      3. 返回值为另外两个:Task基础上还设置Task的Result属性。
  2. 调用方法内
    • 从异步方法获取Task对象,需要值的时候就访问Result属性。

3.2.3 取消一个异步

3.2.4 调用方法中同步地等待

3.2.5 调用方法中异步地等待

3.2.6 Task.Delay

实质是创建了一个Task对象,该对象将暂停其在线程中的处理。异步中的等待请使用delay。

  • 单独 Task.Delay():线程创建了个新的任务去执行延时,线程将继续进行。
  • await Task.Delay():线程将等待这个新任务延时完再继续执行代码。
  • Thread.Sleep()只是把CPU时间片分出去了,实际上还是占有资源;而await Task.Delay()是用的完成端口,延时过程不会占用资源,开始延时和延时完成后的线程可能是两个不同的线程。

3.2.7 异步Lambda

标签:异步,Task,进阶,C#,await,线程,方法,Socket
From: https://www.cnblogs.com/LASER-06/p/16818232.html

相关文章