async和await详解

1.非UI线程中执行

Test()函数带有async 和await ,返回值写成Task。
 1 using System;
2 using System.Threading;
3 using System.Threading.Tasks;
4
5 namespace _00_测试
6 {
7 class Program
8 {
9 static void Main(string[] args)
10 {
11 Console.WriteLine($"Main Start:{Thread.CurrentThread.ManagedThreadId}");
12 Task task = Test();
13 Console.WriteLine($"Main End:{Thread.CurrentThread.ManagedThreadId}");
14 Console.ReadKey();
15 }
16 private async static Task Test()
17 {
18 Console.WriteLine($"当前主线程ID::{Thread.CurrentThread.ManagedThreadId}");
19 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
20 Task task1 = Task.Factory.StartNew(() =>
21 {
22 Thread.Sleep(100);
23 Console.WriteLine($"task1:{Thread.CurrentThread.ManagedThreadId}");
24 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
25 });
26 await task1;
27
28 Console.WriteLine($"task1 结束后的线程ID:{Thread.CurrentThread.ManagedThreadId}");
29 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
30
31 await Task.Run(() =>
32 {
33 Thread.Sleep(100);
34 Console.WriteLine($"task2:{Thread.CurrentThread.ManagedThreadId}");
35 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
36 });
37 Console.WriteLine($"Test End:{Thread.CurrentThread.ManagedThreadId}");
38 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
39 }
40 }
41 }

上面是控制台应用程序,主线程的ID为1,第一个await和后面的代码都是子线程完成的。第二个await和后面的代码,也是子线程完成的。在非UI线程中执行的async异步方法,await等待的异步操作和后面要执行的代码,都是从线程池获取一个线程来执行的。

2.UI线程中执行

 1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.Linq;
7 using System.Text;
8 using System.Threading;
9 using System.Threading.Tasks;
10 using System.Windows.Forms;
11
12 namespace _009__数据库
13 {
14 public partial class Form1 : Form
15 {
16 public Form1()
17 {
18 InitializeComponent();
19 }
20
21 private async void button1_Click(object sender, EventArgs e)
22 {
23 Console.WriteLine($"Main Start:{Thread.CurrentThread.ManagedThreadId}");
24 Task task = Test();
25 await task;
26 Console.WriteLine($"Main End:{Thread.CurrentThread.ManagedThreadId}");
27 Console.ReadKey();
28 }
29 private async static Task Test()
30 {
31 Console.WriteLine($"当前主线程ID::{Thread.CurrentThread.ManagedThreadId}");
32 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
33 Task task1 = Task.Factory.StartNew(() =>
34 {
35 Thread.Sleep(100);
36 Console.WriteLine($"task1:{Thread.CurrentThread.ManagedThreadId}");
37 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
38 });
39 await task1;
40
41 Console.WriteLine($"task1 结束后的线程ID:{Thread.CurrentThread.ManagedThreadId}");
42 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
43
44 await Task.Run(() =>
45 {
46 Thread.Sleep(100);
47 Console.WriteLine($"task2:{Thread.CurrentThread.ManagedThreadId}");
48 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
49 });
50 Console.WriteLine($"Test End:{Thread.CurrentThread.ManagedThreadId}");
51 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
52 }
53 }
54 }

在UI线程中,async切换线程的规律和非UI线程不一样了。在UI线程中,await后面紧跟的代码,一直都是在UI线程中执行的。

注意:非UI线程中,await后面的动作都是子线程完成的;UI线程中,await后面的动作都是主线程完成的。

3.带返回值的异步方法

非UI线程

 1 using System;
2 using System.Threading;
3 using System.Threading.Tasks;
4
5 namespace _00_测试
6 {
7 class Program
8 {
9 static void Main(string[] args)
10 {
11 Console.WriteLine($"Main Start:{Thread.CurrentThread.ManagedThreadId}");
12 Task<int> task = Test();
13 Console.WriteLine($"结果为:{task.Result}");
14 Console.WriteLine($"Main End:{Thread.CurrentThread.ManagedThreadId}");
15 Console.ReadKey();
16 }
17 private async static Task<int> Test()
18 {
19 int Value = 0;
20 Task task1 = Task.Factory.StartNew(() =>
21 {
22 Value++;
23 Thread.Sleep(100);
24 });
25 await task1;
26 return Value;
27 }
28 }
29 }

执行Test()异步方法,然后获取异步方法的返回值,执行异步方法的线程会一直阻塞,直到等到要获取的返回值。但是,在UI线程中,执行异步方案的是主线程,直接就死锁了。

UI线程

 1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.Linq;
7 using System.Text;
8 using System.Threading;
9 using System.Threading.Tasks;
10 using System.Windows.Forms;
11
12 namespace _009__数据库
13 {
14 public partial class Form1 : Form
15 {
16 public Form1()
17 {
18 InitializeComponent();
19 }
20
21 private void button1_Click(object sender, EventArgs e)
22 {
23 Console.WriteLine($"Main Start:{Thread.CurrentThread.ManagedThreadId}");
24 Task<int> task = Test();
25 Console.WriteLine($"结果为:{task.Result}");
26 Console.WriteLine($"Main End:{Thread.CurrentThread.ManagedThreadId}");
27 Console.ReadKey();
28 }
29 private async static Task<int> Test()
30 {
31 int Value = 0;
32 Task task1 = Task.Factory.StartNew(() =>
33 {
34 Value++;
35 Thread.Sleep(100);
36 });
37 await task1;
38 return Value;
39 }
40 }
41 }

在winform中,点击按钮,界面直接卡死了!!!

分析, 执行Test()异步方法,然后获取异步方法的返回值,但是在UI线程中,await后面的操作是UI线程执行的。那么,首先异步方法执行了await中的异步任务,UI线程已经开始等这个执行结果了,UI线程阻塞等待中;而await后面的

return Value;这一行,需要UI线程执行啊,此时UI线程阻塞等结果呢无法执行其他操作,就这么UI等返回值,子线程等UI线程等UI线程来执行  return Value;这行代码。谁也不让谁的等待下去,这就是死锁了。

async和await详解的更多相关文章

  1. async与await详解

    async和await只是编译器功能.编译器会用Task类创建代码.如果不适用这两个关键字,也可以用C#4.0和Task类实现同样的功能,只是没有那么方便. 题主在概念上确实混淆的不行,但是确实asy ...

  2. Promise和async await详解

    本文转载自Promise和async await详解 Promise 状态 pending: 初始状态, 非 fulfilled 或 rejected. fulfilled: 成功的操作. rejec ...

  3. JavaScript中的async/await详解

    1.前言 ​ async函数,也就是我们常说的async/await,是在ES2017(ES8)引入的新特性,主要目的是为了简化使用基于Promise的API时所需的语法.async和await关键字 ...

  4. C#多线程和异步(二)——Task和async/await详解

    一.什么是异步 同步和异步主要用于修饰方法.当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行,我们称这个方法是同步方法:当一个方法被调用时立即返回,并获取一个线程执行该方法内部的业务 ...

  5. C#多线程和异步(二)——Task和async/await详解(转载)

    一.什么是异步 同步和异步主要用于修饰方法.当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行,我们称这个方法是同步方法:当一个方法被调用时立即返回,并获取一个线程执行该方法内部的业务 ...

  6. 关于async function(){ let res = await } 详解

    本文引自: https://www.jianshu.com/p/435a8b8cc7d3 async function fn(){ //表示异步,这个函数里面有异步任务 let result = aw ...

  7. Task和async/await详解

    一.什么是异步 同步和异步主要用于修饰方法.当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行,我们称这个方法是同步方法:当一个方法被调用时立即返回,并获取一个线程执行该方法内部的业务 ...

  8. C#多线程和异步——Task和async/await详解

    阅读目录 一.什么是异步 二.Task介绍 1 Task创建和运行 2 Task的阻塞方法(Wait/WaitAll/WaitAny) 3 Task的延续操作(WhenAny/WhenAll/Cont ...

  9. async await详解

    async await本身就是promise + generator的语法糖. 本文主要讲述以下内容 async awiat 实质 async await 主要特性 async await 实质 下面 ...

随机推荐

  1. Java学习,利用IDEA开发工具连接redis

    Idea连接redis及Jedis数据操作 注意是否开启了redis服务!!! 1.打开虚拟机终端,查看虚拟机防火墙是否关闭 查看防火墙当前状态命令: $sudo ufw status 我的是默认关闭 ...

  2. [Java反序列化]jdk原生链分析

    jdk原生链分析 原文链接 作为jdk中目前发现的原生链,还是有必要要分析这个用法的.全文仅限尽可能还原挖掘思路 JDK7u21 在很多链中,TemplatesImpl一直发挥着不可或缺的作用,它是位 ...

  3. 167. Two Sum II - Input array is sorted - LeetCode

    Question 167. Two Sum II - Input array is sorted Solution 题目大意:和Two Sum一样,这里给出的数组是有序的 思路:target - nu ...

  4. SpringBoot从Eclipse添加的Tomcat容器中启动

    SpringBoot的Web项目,想要在Eclipse中的Tomcat容器中启动运行需要做下面这两处改动 pom.xml <packaging>war</packaging> ...

  5. Cocos---大作业:简单H5小游戏

    Cocos大作业:传统美食分分类 知识点清单: 场景切换,监听时间,碰撞组件及回调,拖动角色移动,分数记录,随机数和定时器,背景音乐控制,资源池控制,预制体,进度条... 源码+q:143144832 ...

  6. CSAPP 之 ShellLab 详解

    前言 本篇博客将会详细介绍 CSAPP 之 ShellLab 的完成过程,实现一个简易(lou)的 shell.tsh 拥有以下功能: 可以执行外部程序 支持四个内建命令,名称和功能为: quit:退 ...

  7. 声学感知刻度(mel scale、Bark scale、ERB)与声学特征提取(MFCC、BFCC、GFCC)

    梅尔刻度 梅尔刻度(Mel scale)是一种由听众判断不同频率 音高(pitch)彼此相等的感知刻度,表示人耳对等距音高(pitch)变化的感知.mel 刻度和正常频率(Hz)之间的参考点是将1 k ...

  8. Redis - 为什么 Redis 是单线程的?

    Redis中work线程是单线程的.也就是对于业务数据的操作是单线程的. Redis中存在多线程操作 异步关闭文件 异步将缓冲区冲洗到磁盘文件中 异步删除键值对 Redis是基于内存的,所以cpu不是 ...

  9. ACL权限控制

    ALC讲述比较详细 https://zhuanlan.zhihu.com/p/360158311

  10. JavaScript 防盗链的原理以及破解方法

    先说说防盗链的原理,http 协议中,如果从一个网页跳到另一个网页,http 头字段里面会带个 Referer.这里的Referer是由于历史原因导致了拼写错误 后来也就一直沿用.图片服务器通过检测 ...