本文讨论,通过将Lambda还原成最普通的代码段,来解释上篇提出的疑问。并更正上篇中一些不太正确的写法。最后会给出无需等待Async方法返回值时,对Async方法使用await的建议,供大家参考。
第一篇传送门:await使用中的阻塞和并发
首先我们比较以下三段代码,其中第一和第三可以做到并发执行,第二个是线性的执行。
//并发
public async Task Await3Task()
{
var task3 = Delay3000Async();
var task2 = Delay2000Async();
var task1 = Delay1000Async();
await task3;
await task2;
await task1;
}
//非并发
public async Task Await3DelayAsync()
{
await Delay3000Async();
await Delay2000Async();
await Delay1000Async();
}
//并发,这里甚至可以把var task3等去掉,直接调用xxxAsync(),只是会出现警告的波浪罢了
public void NoAwait3Task()
{
var task3 = Delay3000Async();
var task2 = Delay2000Async();
var task1 = Delay1000Async();
}
//这里补充一下调用的三个Async方法 public async Task Delay3000Async()
{
await Task.Delay(3000);
Console.WriteLine(3000);
Console.WriteLine(DateTime.Now);
}
public async Task Delay2000Async()
{
await Task.Delay(2000);
Console.WriteLine(2000);
Console.WriteLine(DateTime.Now);
}
public async Task Delay1000Async()
{
await Task.Delay(1000);
Console.WriteLine(1000);
Console.WriteLine(DateTime.Now);
}
这里我们可以看出,await和并发木有关系,隐式的并发执行是由async方法决定的。而await是用于主动的阻塞,期望等待方法结束才继续运行时使用。
以下2个方法的执行结果是一样的,都可以并发执行。可以看出,把仅仅希望并发执行,不需要返回结果的方法丢到List里,然后Foreach是毫无意义的……所以上篇其实是干了一些蠢事情……
public void AwaitTaskList()
{
var tasks = new List<Task>
{
Delay3000Async(),
Delay2000Async(),
Delay1000Async()
};
tasks.ForEach(async _ => await _);
}
public void NoAwaitTaskList()
{
var tasks = new List<Task>
{
Delay3000Async(),
Delay2000Async(),
Delay1000Async()
};
}

上篇提到Task在创建的时候,就已经开始运行了。而await仅仅是出现在需要等待结果的地方。所以如果无需等待,就不要写await了……貌似上篇又干了一些蠢事……
//非并发
public async Task Await3Func()
{
Func<Task> func3 = Delay3000Async;
Func<Task> func2 = Delay2000Async;
Func<Task> func1 = Delay1000Async;
await func3();
await func2();
await func1();
}
//并发
public void NoAwait3Func()
{
Func<Task> func3 = Delay3000Async;
Func<Task> func2 = Delay2000Async;
Func<Task> func1 = Delay1000Async;
func3();
func2();
func1();
}
同时我本人对List<Func<Task》尚未创建Task却可以并发表示疑问,接下来给出解答。下面分别贴出了使用Lambda和不使用的情况。我们可以清楚的看到Lambda表达式具体帮我们省略了什么。
//使用Lambda
public void AwaitFuncTaskList()
{
var funcList = new List<Func<Task》()
{
Delay3000Async,
Delay2000Async,
Delay1000Async
};
funcList.ForEach(async _ => await _());
}
//不使用Lambda
public void AwaitFuncTaskListNoLambda()
{
var funcList = new List<Func<Task》()
{
Delay3000Async,
Delay2000Async,
Delay1000Async
};
//funcList.ForEach(AwaitAction());
foreach(var func in funcList)
{
AwaitAction()(func);
}
}
public Action<Func<Task》 AwaitAction()
{
return async _ => await _();
}
根据上文的总结,可以看出虽然await造成了阻塞,但并不是在主线程等待,所以我们幸运的并发了……
再看下面一段,我干脆拿掉了await,毫无疑问的并发执行了。上篇让人汗颜的事情貌似还干了不少,好在我脸皮厚,不会删掉前一篇的随笔,哈哈哈哈……
public void NoAwaitFuncTaskList()
{
var funcList = new List<Func<Task》()
{
Delay3000Async,
Delay2000Async,
Delay1000Async
};
funcList.ForEach(_ => _());
}
public void NoAwaitFuncTaskListNoLambda()
{
var funcList = new List<Func<Task》()
{
Delay3000Async,
Delay2000Async,
Delay1000Async
};
//funcList.ForEach(NoAwaitAction());
foreach(var func in funcList)
{
NoAwaitAction()(func);
}
}
public Action<Func<Task》 NoAwaitAction()
{
return _ => _();
}
仔细看一下可以发现,为了懒惰而使用的ForEach其实增加了多余的一层Action<Func<Task》,如果直接使用foreach会是如下的情况:
public void NoAwaitFuncTaskWithoutForeachExtension() www.yztrans.com 
{
var funcList = new List<Func<Task》()
{
Delay3000Async,
Delay2000Async,
Delay1000Async
};
foreach (var func in funcList)
{
func();
}
}
接下来是总结陈述:
async用于异步,可以优美的替代Thread、BackgroundWorker和Task.Run等写法。
await用于等待。一定是在你主动希望阻塞并等待返回结果时才使用。
在async方法里,Task在创建时就开始运行了 www.lefeng123.com
写Lamdba别把自己写晕了……

转载于:https://www.cnblogs.com/tianchaoy/p/3554453.html

await使用中的阻塞和并发相关推荐

  1. await使用中的阻塞和并发(一)

    好吧,不加点陈述不让发首页.那我们来陈述一下本篇提到的问题和对应的方法. 在.NET4.5中,我们可以配合使用async和await两个关键字,来以写同步代码的方式,实现异步的操作. 好处我目前看来有 ...

  2. 15分钟读懂进程线程、同步异步、阻塞非阻塞、并发并行,太实用了!

    作者:Martin cnblogs.com/mhq-martin/p/9035640.html 基本概念 1 进程和线程 进程(Process): 是Windows系统中的一个基本概念,它包含着一个运 ...

  3. python非阻塞多线程socket_Python实现web服务器之 单进程单线程非阻塞实现并发及其原理...

    在Python实现web服务器入门学习多进程.多线程实现并发HTTP服务器中,我们知道可以分别通过多进程.多线程的方式实现并发服务器,那么,是否可以通过单进程单线程的程序实现类似功能呢? 实际上,在P ...

  4. 15分钟读懂进程线程、同步异步、阻塞非阻塞、并发并行

    基本概念 1 进程和线程 进程(Process): 是Windows系统中的一个基本概念,它包含着一个运行程序所需要的资源.一个正在运行的应用程序在操作系统中被视为一个进程,进程可以包括一个或多个线程 ...

  5. 进程线程、同步异步、阻塞非阻塞、并发并行、多线程

    一: 进程和线程 1: 进程(Process) 是Windows系统中的一个基本概念,它包含着一个运行程序所需要的资源.一个正在运行的应用程序在操作系统中被视为一个进程,进程可以包括一个或多个线程.线 ...

  6. 队列阻塞_Java并发|阻塞队列ArrayBlockingQueue解析

    之前的文章我们学了 ConcurrentHashMap. ConcurrentLinkedQueue 等线程安全容器,而且也说了 Java并发包中的 Concurent 开头的并发容器都是非阻塞的,是 ...

  7. CountDownLatch 的 .await() 的线程阻塞 和countDown() 计时唤醒

    1.CountDownLatch end = new CountDownLatch(N); //构造对象时候 需要传入参数N 2.end.await()  能够阻塞线程 直到调用N次end.count ...

  8. 多线程编程:阻塞、并发队列的使用总结

    最近,一直在跟设计的任务调度模块周旋,目前终于完成了第一阶段的调试.今天,我想借助博客园平台把最近在设计过程中,使用队列和集合的一些基础知识给大家总结一下,方便大家以后直接copy.本文都是一些没有技 ...

  9. Linux下套接字详解(五)----基于fork多进程的TCP套接字(阻塞/同步/并发)

    简介 一个简单的改进方案是在服务器端使用多线程(或多进程).多线程(或多进程)的目的是让每个连接都拥有独立的线程(或进程),这样任何一个连接的阻塞都不会影响其他的连接.具体使用多进程还是多线程,并没有 ...

最新文章

  1. 【进阶版九宫格背景图片】如何仅仅依靠background的几个属性组合搭配出酷炫的背景图片效果,并自适应任何宽高效果?
  2. redmine3.3.1安装与常用插件安装
  3. 我的世界java1.15.2光影_快去打卡吧!海南首个“360光影馆”落户三亚
  4. C语言执行shellcode的五种方法
  5. SAP UI的加载动画效果和幽灵设计(Ghost Design)
  6. CSS3笔记之定位篇(一)relative
  7. android模拟器上传,电脑文件怎么传到夜神android模拟器 文件上传夜神模拟器
  8. php通过ajax下载文件,通过Ajax如何请求下载Execl文件
  9. ISA 2004 Site-To-Site ×××截图详解
  10. 苹果Mac软件开发工具:Xcode 让开发者如虎添翼
  11. 更改计算机复制快捷键,电脑上怎么把一句话设置快捷键,电脑快捷键复制一句话-...
  12. hdu 6377 度度熊看球赛 (dp)
  13. 【FPGA教程案例13】基于vivado核的CIC滤波器设计与实现
  14. win7动态壁纸_壁纸软件推荐-wallpaper engine
  15. 2022年全球与中国低压配电系统市场现状及未来发展趋势
  16. 基于模糊聚类的图像分割
  17. Windows 7 SP1相关资源下载
  18. 《变形金刚ONLINE》策划案
  19. UE4 第三人称完全流程
  20. python中的除法运算定律_四年级上册数学《运算定律》教学总结(精选6篇)

热门文章

  1. 网络编程之IO多路复用
  2. python中float什么意思_在python中 float是什么意思?
  3. IDEA 社区版 DB Brower SQL语句运行
  4. 「OceanBase 4.1 体验」|国产分布式数据库不好用?别再打脸了
  5. 请把ios文件解压出来是什么意思_全球首款 iOS 模拟器 “黑雷iOS模拟器”
  6. 云原生之使用Docker部署Dailynotes个人笔记管理工具
  7. MySQL报错 由于找不到msvcp120.dll
  8. Kudu+Impala介绍
  9. C#总是报未能加载文件或程序集
  10. 微信小程序中 setData 详解