未完成,不定时更新
一、进程与线程
平时写简单程序的时候都是单线程,编译器只给程序分配一个主线程。
但是后续随着难度增加,程序功能的复杂,主线程一拳难敌四手,容易造成程序假死。
于是我们需要创建线程,来执行程序的部分功能。
1.1 前台线程与后台线程
前台线程:
由 Thread 类创建的线程默认是前台线程。所有前台线程关闭后,程序才能关闭。
后台线程:
只要所有前台线程结束,后台线程自动强制结束。
1.2 线程定义
Thread th = new Thread(方法名);//线程定义
th.IsBackground = true; //设置为后台线程(默认为前台线程)
th.Start(); //线程待命(方法如果是带参数的,在start里面填参数
// 而且必须是object类型)
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、调用方法内
- 异步方法内:
- 异步执行await空闲任务;
- await完成后,执行后续部分;
- 遇到return、末尾时:
- 返回类型void:控制流退出
- 返回类型Task;设置Task状态属性后退出
- 返回值为另外两个:Task基础上还设置Task的Result属性。
- 调用方法内:
- 从异步方法获取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()
是用的完成端口,延时过程不会占用资源,开始延时和延时完成后的线程可能是两个不同的线程。