C#中await/async用法

15 篇文章 0 订阅

1 引言

官方文档:https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/async

看微软的官方文档看的头大,比较晦涩的,反正我是啃不动,这里通俗的解释一下c# 中的await/async

2 await/async是什么

说白了await/async就是一个语法糖,单纯使用await/async并不会创建一个线程,创建线程的这个操作由是线程池决定的。

那么我们为啥还要使用await/async呢?

答:为了更好的编写异步操作,也就是识别性更高

3 错误的调用异步方法

3.1 方法上只添加async,但内部未使用Task.Run

在这里插入图片描述
可以看到,单纯在方法上添加async,是不会执行异步的。

想要异步,还需要在方法内部使用Task.Run或者创建线程。

3.2 方法内部未处理返回值

在这里插入图片描述
可以看到,CalculateSum方法内部的Task.Run,并没有阻塞,也就是我们并没得到异步线程计算后c的值。

如果我们在方法上加async呢?结果是一致的。
在这里插入图片描述

4 使用await等待Task.Run的结果

我们在原有的Task.Run前面加await,发现报错
在这里插入图片描述
所以我们需要这么做,在CalculateSum方法上添加async关键词,这时候又报错了。
在这里插入图片描述
因为我们是有返回值的,异步方法的返回值只能是void,Task,或者Task< T >,我们添加返回值Task< int >
在这里插入图片描述

5 如何调用我们写的异步方法

经过上面的错误操作后,这时我们的异步方法已经写好了,如下

Console.WriteLine("start");
CalculateSum(1, 2);
CalculateSum(1, 2);
CalculateSum(1, 2);
CalculateSum(1, 2);
Console.WriteLine("end");
Console.ReadKey();
public static class MThread
{
    public static async Task<int> CalculateSum(int a, int b)
    {
        int c = 0;
        await Task.Run(() =>
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId+":start");
            Thread.Sleep(1000 * 3);
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId+":end");
            c= a + b;
        });
        Console.WriteLine("计算结果:"+c);
        return c;
    }
}

运行结果:
在这里插入图片描述

我们发现,实现的异步的效果,主线程没有被阻塞。

那么又有问题了,我们的异步方法是有返回值的,主线程没有被阻塞我们如何得到返回值呢,接着往下看。

6 得到异步方法的返回值。

6.1 通过Task.Result阻塞获得返回值

代码:

Console.WriteLine("start");
Task<int> task = CalculateSum(1, 2);
Task<int> task2 = CalculateSum(1, 2);
Task<int> task3 = CalculateSum(1, 2);
Task<int> task4 = CalculateSum(1, 2);
Console.WriteLine("end");
Console.WriteLine("开始等待返回结果");
Console.WriteLine(task.Result);
Console.WriteLine(task2.Result);
Console.WriteLine(task3.Result);
Console.WriteLine(task4.Result);
Console.WriteLine("等待返回结果完毕,程序结束");
public static class MThread
{
    public static async Task<int> CalculateSum(int a, int b)
    {
        int c = 0;
        await Task.Run(() =>
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId+":start");
            Thread.Sleep(1000 * 3);
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId+":end");
            c= a + b;
        });
        Console.WriteLine("计算结果:"+c);
        return c;
    }
}

结果:
在这里插入图片描述

结论:
主线程没有阻塞,但是调用task.Result时会阻塞,直到该线程返回结果后,阻塞结束

6.2 通过await等待返回值

代码:

Console.WriteLine("start");
int res = await CalculateSum(1, 2);
int res2 = await CalculateSum(1, 2);
int res3 = await CalculateSum(1, 2);
int res4 = await CalculateSum(1, 2);
Console.WriteLine(res);
Console.WriteLine(res2);
Console.WriteLine(res3);
Console.WriteLine(res4);
Console.WriteLine("end");
Console.WriteLine("等待返回结果完毕,程序结束");
public static class MThread
{
    public static async Task<int> CalculateSum(int a, int b)
    {
        int c = 0;
        await Task.Run(() =>
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId+":start");
            Thread.Sleep(1000 * 3);
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId+":end");
            c= a + b;
        });
        Console.WriteLine("计算结果:"+c);
        return c;
    }
}

结果:

在这里插入图片描述
结论:
主线程被await阻塞,直到该线程返回结果后,才向下执行。

7 总结

编写异步方法

  • 编写异步方法时,需要标识async关键词。

  • 编写异步方法时,返回值只能是void,Task,Task<T>

  • 如果返回值是Task。方法体无需有返回值,直接await Task.Run(() =>{});即可

  • 想要异步,必须在方法内部开启新的线程。并且需要await Task.Run(() =>{});

使用异步方法

想要得到异步方法返回值,就需要阻塞,调用await或者T.Result来阻塞异步方法,得到返回值。

异步方法模板

Console.WriteLine("start");
await CalculateSum(1, 2);
Task calculateSum2 = CalculateSum2(1, 2);
CalculateSum3(1, 2);
CalculateSum4(()=>
{
    Console.WriteLine("这是一个异步操作");
});

Console.WriteLine("end");
Console.ReadKey();

public static class MThread
{
    public static async Task<int> CalculateSum(int a, int b)
    {
        int c = 0;
        await Task.Run(() =>
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":start");
            Thread.Sleep(1000 * 3);
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":end");
            c = a + b;
        });
        Console.WriteLine("计算结果:" + c);
        return c;
    }

    public static async Task CalculateSum2(int a, int b)
    {
        int c = 0;
        await Task.Run(() =>
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":start");
            Thread.Sleep(1000 * 3);
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":end");
            c = a + b;
        });
        Console.WriteLine(c);
    }


    public static async void CalculateSum3(int a, int b)
    {
        int c = 0;
        await Task.Run(() =>
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":start");
            Thread.Sleep(1000 * 3);
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":end");
            c = a + b;
        });
        Console.WriteLine(c);
    }

    public static async Task CalculateSum4(Action action)
    {
        await Task.Run(action);
    }
}
  • 6
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
`async` 和 `await` 是 C# 引入的特性,用于简化异步编程,并使得代码在等待异步操作完成之前可以继续执行其他任务。这提高了应用程序的响应性和用户体验。 ### `async` `async` 关键字标记了一个方法,表明这个方法会通过异步方式执行。在异步方法内部,我们可以调用 `await` 来暂停当前协程线程的执行,直到等待的任务完成。这种方法允许其他操作在等待期间继续执行,避免了阻塞主线程的情况。 #### 示例: ```csharp public async Task DoAsyncWork() { // 这里可以编写需要异步执行的代码 // 使用await关键字 await DoSomethingAsync(); // 暂停当前方法的执行,直到DoSomethingAsync()返回结果 // 当DoSomethingAsync()完成后,此处的代码将继续执行 } // 调用异步方法并捕获异常 try { await DoAsyncWork(); } catch (Exception ex) { Console.WriteLine($"发生错误: {ex.Message}"); } ``` ### `await` `await` 关键字用于挂起当前异步方法的执行,等待指定的操作完成。它接收的是 `Task<T>` 类型的对象作为参数,其 T 表示返回值类型。 #### 何时使用 `await`: 1. **处理 I/O 操作**:比如文件读写、网络请求等,它们通常耗时较长,不适合阻塞主线程。 2. **数据库查询**:当从数据库获取数据时,可以使用 `await` 等待查询完成。 3. **计算密集型任务**:如果某个操作需要大量 CPU 时间,则也可以通过 `await` 提高程序效率。 ### `async await` 的优势: - **提高用户体验**:允许 UI 线程执行其他工作,如响应用户输入或更新界面。 - **更清晰的代码结构**:通过将等待操作提取到单独的 `await` 行,可以使代码更容易理解和维护。 - **性能提升**:通过避免长时间阻塞主线程,可以显著改善程序的整体性能。 ### 相关问题: 1. `async await` 怎么处理错误? 2. 应该如何正确地使用 `await` 保证程序的安全性? 3. `async await` 是否适用于所有类型的异步操作?
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

L-960

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值