C#中async和await的深入分析
作者:code?bean 发布时间:2023-09-14 17:11:20
大概理解
查了一个小时的资料:async和await
发现这个大神的解释一针见血,深得我心!以最简单的例子,解释了async和await。妙~~~
大多情况下,分开才能体现async和await的价值!
但,await 并没有这么简单。
深入分析
await和Wait()的区别
接下来继续往下看:
await Task.Delay(3000); 和Task.Delay(3000).Wait(); 有没有区别?
上代码:
using System.Diagnostics;
namespace await_async2
{
internal class Program
{
static public void TestWait()
{
var t = Task.Factory.StartNew(() =>
{
Console.WriteLine("Start");
Task.Delay(3000).Wait();
Console.WriteLine("Done");
});
t.Wait();
Console.WriteLine("All done");
}
static public void TestWait2()
{
var t = Task.Factory.StartNew(async () =>
{
Console.WriteLine("Start");
await Task.Delay(3000);
Console.WriteLine("Done");
});
t.Wait();
Console.WriteLine("All done");
}
static public void TestWait3()
{
var t = Task.Run(async () =>
{
Console.WriteLine("Start");
await Task.Delay(3000);
Console.WriteLine("Done");
});
t.Wait();
Console.WriteLine("All done");
}
static void Main(string[] args)
{
TestWait2();
//避免程序提前退出,导致一些现象看不到
Task.Delay(5000).Wait();
}
}
}
首先,强调一下,最后一句 Task.Delay(5000).Wait(); 是必须的,不然,程序提前退出,导致一些现象看不到,从而蒙蔽了我们。
第1段代码TestWait执行效果,如下:
第2段代码TestWait2执行效果,如下:
第3段代码TestWait3执行效果,如下:
现在给出结论:
Task.Delay(3000).Wait(); 这个就是同步等。
await Task.Delay(3000); 因为没有分开来写(见第一张图),所以基本和同步等没有区别。
但是如果 await Task.Delay(3000); 是写到:Task.Factory.StartNew里面的
static public void TestWait2()
{
var t = Task.Factory.StartNew(async () =>
{
Console.WriteLine("Start");
await Task.Delay(3000);
Console.WriteLine("Done");
});
t.Wait();
Console.WriteLine("All done");
}
那这个效果不一样了,他们执行的权限丢出去了有点像python里的yeild,来看下程序的执行顺序:
这里就看出了:await Task.Delay(3000); 和Task.Delay(3000).Wait(); 的区别了。(但是这种情况如果在道Task.Run里面就体现不出来!)
然后,我有简单做了一个实验:
这就更明了了, await Task.Delay(3000); 就像设置了一个回调,一旦三秒时间一到,程序的指针就会回到await Task.Delay(3000);后面的位置,直到函数执行结束。再回到之前的位置。这就是所谓的用同步的方式写异步的代码吧。
但是,为啥在Task.Factory.StartNew才会体现出来,这个我就不清楚了,请各位大佬指点一下。
去掉Task.Run的Wait
再来对比一下,下面这两个函数:
static public void TestWait8()
{
var t = Task.Run(async () =>
{
Console.WriteLine("Start");
await Task.Delay(3000);
Console.WriteLine("Done");
});
Console.WriteLine("All done");
}
static public void TestWait8_5()
{
var t = Task.Factory.StartNew(async () =>
{
Console.WriteLine("Start");
await Task.Delay(3000);
Console.WriteLine("Done");
});
t.Wait();
Console.WriteLine("All done");
}
先看第一个TestWait8,由于Task.Run不再调用 t.Wait(),Task.Run内部这个线程和主线程是并行的关系。程序指针会在两个线程中来回切换。如果一方中写了await xxx,那程序指针必然跳到另一个线程。直达await结束才可能返回。 这种情形是比较多的。此时await能节省大量等待时间(比如IO操作时间),充分利用等待时间。
此时 Console.WriteLine("All done");会最先被打印出来。
再看第二个TestWait8_5(其实就是回顾一下),当程序执行到t.Wait()时,程序不会继续向下了,(此时因为有t.Wait()的存在,所以子线程其实是优先于主线程的)而是进入到子线程的内部进程,试图将这个线程执行完,但是再线程里面遇到又遇到await Task.Delay(3000);此时程序指针不会再这里死等,程序指针又跳回主线程继续执行,直到三秒到了之后就会回到子线程,子线程执行完了之后,再回到主线程。
但是如果吧TestWait8_5 中 Task.Factory.StartNew 换成 Task.Run ,那么前面的过程一样,只是执行到await Task.Delay(3000);时候,此时会死等,不会跳到主线程,而是一定等到这个子线程完结,再回主线程。
小结
总结一下就是,遇到await 一定会等,至于程序指针是先跳到其他线程,还是在此线程死等,就看你的线程函数这么写的了。
其他
.Await();
最后,还有个:Task.Delay(3000).Await();
这个是prsim对Task写的的一个拓展方法(避免在主线程调用时,阻塞UI):
来源:https://blog.csdn.net/songhuangong123/article/details/127627231


猜你喜欢
- 无障碍服务可以模拟一些用户操作,无障碍可以处理的对象,通过类 AccessibilityNodeInfo 表示,通过无障碍服务,可以通过它的
- 目录简介普通邮件导入javax.mail依赖Spring配置类邮件配置:mail.properties测试基于thymeleaf模版的邮件导
- 由于我们在eclipse ee中把项目部署在web端经常会出现报404错误。原因为:404状态码是一种http状态码,其意思是: 所请求的页
- RibbonRibbon 是 Netflix开源的基于HTTP和TCP等协议负载均衡组件Ribbon 可以用来做客户端负载均衡,调用注册中心
- 介绍本篇给大家带了的是ViewFlipper,它是Android自带的一个多页面管理控件,且可以自动播放! 和ViewPager不同,Vie
- transferTo(File file)的路径问题今天看到layui的文件上传的控件,就尝试了一下。简单创建了一个SpringMVC项目。
- 最近公司项目中有一个类似滴滴出行填写验证码的弹框,下面是我撸出来的效果: 中间的那个输入密码的6个框框其实就是用shape画的背景
- 可以用抽象工厂模式来造车。车的品牌有很多,而且车的属性也不少,比如车的类型、排量、门的数量,等等。可以提炼出有关车的一个抽象类:public
- SSM框架是JavaWeb必学的框架,虽说基本的增删改查很简单,但是当面临一些特殊情况时,有时还是会显得手足无措,此篇用来记录一些特殊场景下
- 以前用序列化都是一些方法需要才实现的,后来业务需求要深拷贝才去研究。参阅了别人博客得出一些总结。序列化是为了把Java对象转化为字节序列(字
- 本文实例讲述了C#反射应用。分享给大家供大家参考。具体如下:通过反射实现多系统数据库的配置通过定义接口,反射实例化配置的节点的值配置App.
- 在layout文件中使用自定义的View时遇到如下错误:12-11 17:28:26.962: ERROR/AndroidRuntime(1
- 设立一个定时器tmrMonitor,该定时器会在程序运行时不断把程序的占用内存和占用线程数写到LOG\MEM目录下。我设置的定时器间隔是30
- 第一种最简单,但没有考虑线程安全,在多线程时可能会出问题,不过俺从没看过出错的现象,表鄙视我……public class Singleton
- 1、conditional注解介绍含义: 基于条件的注解作用: 根据是否满足某一个特定条件来决定是否创建某个特定的bean意义: Sprin
- 绘制模糊数学中隶属函数分布图using System; using System.Collect
- 说明:.NET Compact Framework 中不支持异步委托调用,也就是 BeginInvoke 和 EndInvoke 方法。Be
- 示例【通过班级查询老师信息】创建t_classes创建t_classessTeacher创建t_teacher创建Classespackag
- 如何传入字符串参数,分割并遍历如前台传入字符串参数 String str = "a,b,c,d,e,f";现需
- 目录(?)[-]一扩展javalangThread类二实现javalangRunnable接口三Thread和Runnable的区别四线程状