.NET异步和多线程系列(六)- async/await

proginn468312

共 5298字,需浏览 11分钟

 ·

2020-09-12 19:50

本文是.NET异步和多线程系列的第六章,本章主要对之前介绍过的async/await做一些补充说明。

下面我们直接来看下代码和运行结果:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace MyAsyncAwait
{
///
/// await/async 是C#保留关键字,通常是成对出现,语法糖。
///
/// 主线程调用async/await方法,主线程遇到await返回执行后续动作,
/// await后面的代码会等着Task任务的完成后再继续执行
/// 其实就像把await后面的代码包装成一个ContinueWith的回调动作
/// 然后这个回调动作可能是Task线程,也可能是新的子线程,也可能是主线程
///
/// 一个async方法,如果没有返回值,可以方法声明返回Task
/// await/async能够用同步的方式编写代码,但又是非阻塞的。
///
/// async方法在编译后会生成一个状态机(实现了IAsyncStateMachine接口)
///

class Program
{
static void Main(string[] args)
{
Console.WriteLine($
"当前主线程开始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
AwaitAsyncClass.TestShow();
Console.WriteLine($
"当前主线程结束 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Console.ReadKey();
}
}

///
/// await/async关键字 语法糖
/// await/async 要么不用 要么用到底
///

public class AwaitAsyncClass
{
public static void TestShow()
{
Test();
}

private async static Task Test()
{
Console.WriteLine($
"Test开始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");

Task
<long> t = SumAsync();
Console.WriteLine($
"遇到await主线程回来干活了 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");

{
long lResult = await t; //await后面的代码会由线程池的线程执行,非阻塞。
Console.WriteLine($"最终得到的lResult={lResult}");
}

{
//t.Wait(); //主线程等待Task的完成,阻塞的
//long lResult = t.Result; //访问Result,主线程等待Task的完成,阻塞的,效果跟t.Wait()一样
//Console.WriteLine($"最终得到的lResult={lResult}");
}

Console.WriteLine($
"Test结束 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
}

///
/// 带返回值的Task
/// 要使用返回值就一定要等子线程计算完毕
///

private static async Task<long> SumAsync()
{
Console.WriteLine($
"SumAsync start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
long result = 0;

//await后面的代码会等着Task任务的完成后再继续执行
//其实就像把await后面的代码包装成一个ContinueWith的回调动作
//然后这个回调动作可能是Task线程,也可能是新的子线程,也可能是主线程
await Task.Run(() =>
{
for (int k = 0; k < 2; k++)
{
Console.WriteLine($
"SumAsync 第1个 await Task.Run k={k} ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(
1000);
}
for (long i = 0; i < 999_999_999; i++)
{
result
+= i;
}
});

Console.WriteLine($
"SumAsync 第1个 await Task.Run的后续任务开始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
await Task.Run(() =>
{
for (int k = 0; k < 2; k++)
{
Console.WriteLine($
"SumAsync 第2个 await Task.Run k={k} ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(
1000);
}
for (long i = 0; i < 999_999_999; i++)
{
result
+= i;
}
});

Console.WriteLine($
"SumAsync 第2个 await Task.Run的后续任务开始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
await Task.Run(() =>
{
for (int k = 0; k < 2; k++)
{
Console.WriteLine($
"SumAsync 第3个 await Task.Run k={k} ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(
1000);
}
for (long i = 0; i < 999_999_999; i++)
{
result
+= i;
}
});

Console.WriteLine($
"SumAsync end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
return result;
}
}
}

运行结果如下:

仔细观察结果会发现

  主线程调用async/await方法,主线程遇到await后会返回执行后续动作;

  await后面的代码会等着Task任务的完成后再继续执行,其实就像把await后面的代码包装成一个ContinueWith的回调动作;

  然后这个回调动作可能是Task线程,也可能是新的子线程,也可能是主线程;

  await/async能够用同步的方式编写代码,但又是非阻塞的。

下面我们调整下Test方法后再运行(红色的为调整部分):

private async static Task Test()
{
Console.WriteLine($
"Test开始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");

Task
<long> t = SumAsync();
Console.WriteLine($
"遇到await主线程回来干活了 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");

{
//long lResult = await t; //await后面的代码会由线程池的线程执行,非阻塞。
//Console.WriteLine($"最终得到的lResult={lResult}");

}

{
//t.Wait(); //主线程等待Task的完成,阻塞的
long lResult = t.Result; //访问Result,主线程等待Task的完成,阻塞的,效果跟t.Wait()一样
Console.WriteLine($"最终得到的lResult={lResult}"
);
}

Console.WriteLine($
"Test结束 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
}

调整后运行结果如下:

仔细观察结果会发现

  访问Result,主线程会等待Task的完成,阻塞的。

其实async方法在编译后会生成一个状态机(实现了IAsyncStateMachine接口),有兴趣的可以自行去了解下。

至此本文就介绍完了,有兴趣的还可以看下我之前写过一篇也是关于async/await的文章:https://www.cnblogs.com/xyh9039/p/11391507.html

 

Demo源码:

链接:https://pan.baidu.com/s/1jnG5IpteuKCdmF6-tr--cA
提取码:3onm

此文由博主精心撰写转载请保留此原文链接:https://www.cnblogs.com/xyh9039/p/13622122.html

版权声明:如有雷同纯属巧合,如有侵权请及时联系本人修改,谢谢!!!

版权申明:本文来源于网友收集或网友提供,如果有侵权,请转告版主或者留言,本公众号立即删除。


浏览 44
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报