当前位置: 首页 > article >正文

.NET 异步编程(异步方法、异步委托、CancellationToken、WhenAll、yield)

文章目录

    • 异步方法
    • 异步委托
    • async方法缺点
    • CancellationToken
    • WhenAll
    • yield

异步方法

“异步方法”:用async关键字修饰的方法

  1. 异步方法的返回值一般是Task<T>,T是真正的返回值类型,Task<int>。惯例:异步方法名字以 Async 结尾。
  2. 即使方法没有返回值,也最好把返回值声明为非泛型的Task。
  3. 调用泛型方法时,一般在方法前加上await,这样拿到的返回值就是泛型指定的T类型;
  4. 异步方法的“传染性”:一个方法中如果有await调用,则这个方法也 必须修饰为async
static async Task Main(string[] args)
{
     string fileName = "d:/1.txt";
     File.Delete(fileName);
     File.WriteAllTextAsync(fileName, "hello async");
     string s = await File.ReadAllTextAsync(fileName);
     Console.WriteLine(s);
}
static async Task<int> DownloadAsync(string url, string destFilePath)
{
    string body;
    using (HttpClient httpClient = new HttpClient())
    {
        body = await httpClient.GetStringAsync(url);
    }
    await File.WriteAllTextAsync(destFilePath, body);
    return body.Length;
}

如果同样的功能,既有同步方法,又有异步方法,那么 首先使用异步方法。.NET5中,很多框架中的方法也都支持异步:Main、WinForm事件处理函数。
对于不支持的异步方法怎么办?Wait()(无返回值);Result(有返回值)。风险:死锁,尽量不用。

Tips:async是提示编译器为异步方法中的await代码进行分段处理的,而一个异步方法是否修饰了async对于方法的调用者来讲没区别的,因此对于接口中的方法或者抽象方法不能修饰为async

异步委托

ThreadPool.QueueUserWorkItem(async(obj) => {
   await SomeAsync();
 });

用ILSpy反编译dll(.exe只是windows下的启动器)成C# 4.0版本,就能看到容易理解的底层IL代码。
awaitasync是“语法糖”,最终编译成“状态机调用”。

在这里插入图片描述

总结:async的方法会被C#编译器编译成一个类,会主要根据 await 调用进行切分为多个状态,对async方法的调用会被拆分为对MoveNext的调用。
用await看似是“等待”,经过编译后,其实没有“wait”。

async方法缺点

1、异步方法会生成一个类,运行效率没有普通方法高;
2、可能会占用非常多的线程;

static Task<string> ReadFileAsync(int num)
{
    switch (num)
    {
        case 1:
            return File.ReadAllTextAsync("d:/1.txt");
        case 2:
            return File.ReadAllTextAsync("d:/2.txt");
        default:
            throw new ArgumentException("num invalid");
    }
}

只返回Task,不“拆完了再装”反编译上面的代码:只是普通的方法调用。
优点:运行效率更高,不会造成线程浪费。
返回值为Task的不一定都要标注async,标注async只是让我们可以更方便的await而已。

如果一个异步方法只是对别的异步方法调用的转发,并没有太多复杂的逻辑(比如等待A的结果,再调用B;把A调用的返回值拿到内部做一些处理再返回),那么就可以去掉async关键字。

Tips:如果想在异步方法中暂停一段时间,不要用Thread.Sleep(),因为它会阻塞调用线程,而要用await Task.Delay()

CancellationToken

很多异步方法都有CancellationToken参数,用于获得提前终止执行的信号,比如:请求超时、用户取消请求。

CancellationToken结构体

  • bool IsCancellationRequested: 是否取消
  • Register(Action callback): 注册取消监听
  • ThrowIfCancellationRequested(): 如果任务被取消,执行到这句话就抛异常。

CancellationTokenSource

  • CancelAfter():超时后发出取消信号
  • Cancel(): 发出取消信号
  • CancellationToken Token

ASP.NET Core开发中,一般不需要自己处理CancellationToken、CancellationTokenSource这些,只要做到“能转发CancellationToken就转发”即可。ASP.NET Core会对于用户请求中断进行处理。

WhenAll

Task类的重要方法:

  1. Task<Task> WhenAny(IEnumerable<Task> tasks)等,任何一个 Task完成,Task就完成
  2. Task<TResult[]> WhenAll<TResult>(params Task<TResult>[] tasks)等,所有Task完成,Task才完成。用于等待多个任务执行结束,但是不在乎它们的执行顺序。
  3. FromResult() 创建普通数值的Task对象。
Task<string> t1 = File.ReadAllTextAsync("d:/1.txt");
Task<string> t2 = File.ReadAllTextAsync("d:/2.txt");
Task<string> t3 = File.ReadAllTextAsync("d:/3.txt");
string[] results = await Task.WhenAll(t1, t2, t3);
string s1 = results[0];
string s2 = results[1];
string s3 = results[2];

yield

yield return不仅能够简化数据的返回,而且可以让数据处理“流水线化”,提升性能。

static IEnumerable<string> Test()
{
	yield return "hello";
	yield return "yzk";
	yield return "youzack";
}

在旧版C#中,async方法中 不能用 yield。从C# 8.0 开始,把返回值声明为IAsyncEnumerable(不要带Task),然后遍历的时候用await foreach()即可。

static async Task Main(string[] args)
{
	await foreach(var s in Test())
	{
		Console.WriteLine(s);
	}
}
static async IAsyncEnumerable<string> Test()
{
	yield return "hello";
	yield return "world";
	yield return "youzack";
}

http://www.kler.cn/a/274522.html

相关文章:

  • WPF Binding 绑定
  • 【读书笔记】《论语别裁》寂寞的享受
  • TCP与UDP的端口连通性
  • Java基于SSM框架的无中介租房系统小程序【附源码、文档】
  • ECharts柱状图-柱图42,附视频讲解与代码下载
  • C# cad启动自动加载启动插件、类库编译 多个dll合并为一个
  • 图像分割在疾病诊断中的应用案例
  • 无法加载DLL“SQLite.Interop.dll“:找不到指定模块
  • Linux作业
  • 键盘映射工具KeyTweak的使用,把F9和F10改为 Home、End
  • [PwnThyBytes 2019]Baby_SQL
  • Golang 开发实战day05 - Loops(1)
  • 【智能家居】东胜物联提供软硬一体化智能家居解决方案,助企业提高市场占有率
  • 【计算机网络_网络层】IP协议
  • 卸载.Net SDK
  • ClickHouse列式存储基础笔记
  • BUUCTF-Misc10
  • 搭建基于 Snowflake 的 CI/CD 最佳实践!
  • 【Linux】进程排队的理解进程状态的表述僵尸进程和孤儿进程的理解
  • 六种GPU虚拟化:除了直通、全虚拟化 (vGPU)还有谁?
  • Spark 3.5.0 特性速览
  • 安装tensorflow2.4
  • 【Greenhills】MULTI IDE-GHS最新版本Compiler 23.5.4的兼容性问题
  • 英伟达GTC2024大会开幕,发布机器人003计划,引领具身智能新时代
  • JAVA基础—多线程基础
  • 统计咨询|久菜盒子工作室可实现需求