CS5L7——CSharp 5 功能和语法
CS5L7——CSharp 5 功能和语法
本章代码关键字
1 | async //异步方法关键字 |
C# 5 的新增功能和语法
- 调用方信息特性(C#进阶——特性)
- 异步方法
async
和await
在学习异步方法 async
和 await
之前
我们必须补充一些知识点
- 线程和线程池
- Task类
异步与同步
同步和异步主要用于修饰方法
- 同步方法:
当一个方法被调用时,调用者需要等待该方法执行完毕后返回才能继续执行 - 异步方法:
当一个方法被调用时立即返回,并获取一个线程执行该方法内部的逻辑,调用者不用等待该方法执行完毕
简单理解异步编程,我们会把一些不需要立即得到结果且耗时的逻辑设置为异步执行,
这样可以提高程序的运行效率,避免由于复杂逻辑带来的的线程阻塞
何时需要异步编程
需要处理的逻辑会严重影响主线程执行的流畅性时,我们需要使用异步编程,比如:
- 复杂逻辑计算时
- 网络下载、网络通讯
- 资源加载时等等
异步方法async和await
async
和 await
一般需要配合 Task
进行使用
-
async
用于修饰函数、lambda
表达式、匿名函数 -
await
用于在函数中和async
配对使用,主要作用是等待某个逻辑结束
此时逻辑会返回函数外部继续执行,直到等待的内容执行结束后,再继续执行异步函数内部逻辑
在一个async
异步函数中可以有多个await
等待关键字
1 | void Start() |
使用async
修饰异步方法
- 在异步方法中使用****
await
关键字(不使用编译器会给出警告但不报错),否则异步方法会以同步方式执行(因为在遇到await
前都会同步执行语句) - 异步方法名称建议以
Async
结尾 - 异步方法的返回值只能是
void
、Task
、Task<>
,因为异步方法不能在执行方法后直接返回一个明确的返回值 - 异步方法中不能声明使用
ref
或out
关键字修饰的变量
使用await
等待异步内容执行完毕(一般和Task配合使用),遇到await
关键字时
-
异步方法将被挂起
-
将控制权返回给调用者(即跳出该函数,回到调用者的流程里,就像同步方法
return
了一样,但是异步方法在这里并没有结束) -
当
await
修饰内容异步执行结束后,继续通过调用者线程执行后面内容 -
await
也可以接收方法返回的对象,例如下面的代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16using UnityEngine;
public class L6Test : MonoBehaviour
{
void Start()
{
LoadCubeAsync(Vector3.zero);
}
public async void LoadCubeAsync(Vector3 pos)
{
//请注意,这个await Resources.LoadAsync<GameObject>("Cube")需要第三方插件才能执行!!!
GameObject obj = GameObject.Instantiate(await Resources.LoadAsync<GameObject>("Cube")) as GameObject;
obj.transform.position = pos;
}
}
举例:
-
复杂逻辑计算(利用
Task
新开线程进行计算 计算完毕后再使用 比如复杂的寻路算法)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20void Start()
{
CalcPathAsync(this.gameObject, Vector3.zero);
print("主线程逻辑执行");
}
public async void CalcPathAsync(GameObject obj, Vector3 endPos)
{
print("开始处理寻路逻辑");
int value = 10;
await Task.Run(() =>
{
//模拟复杂逻辑计算
Thread.Sleep(1000);
value = 50;
//这是多线程,也就是说我们不能在多线程里,访问Unity主线程场景中的对象
});
print("寻路完毕,处理逻辑: " + value);
obj.transform.position = endPos;
} -
计时器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28CancellationTokenSource source;
void Start()
{
Timer();
print("主线程逻辑执行");
}
public async void Timer()
{
source = new CancellationTokenSource();
int i = 0;
while (!source.IsCancellationRequested)
{
print(i);
await Task.Delay(1000);
i++;
}
print("计时完成");
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
source.Cancel();
}
} -
资源加载 (
Addressables
的资源异步加载是可以使用async
和await
的)
注意:Unity中大部分异步方法是不支持异步关键字****async
和****await
的,我们只有使用协同程序进行使用
1 | public async void LoadRes() |
虽然官方不支持,但是存在第三方的工具(插件)可以让Unity内部的一些异步加载的方法支持异步关键字
https://github.com/svermeulen/Unity3dAsyncAwaitUtil
虽然Unity中的各种异步加载对异步方法支持不太好
但是当我们用到.Net 库中提供的一些API时,可以考虑使用异步方法
- Web访问:
HttpClient
- 文件使用:
StreamReader、StreamWriter、JsonSerializer、XmlReader、XmlWriter
等等 - 图像处理:
BitmapEncoder、BitmapDecoder
一般.Net 提供的API中 方法名后面带有 Async的方法 都支持异步方法
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 文KRIFE齐的博客!