20181110_wait和async
一. Awit和async的由来:
await/async本身是一个语法糖,编译器提供的一个简化编程的功能; 在C#升级和.net Framework升级的时候, 产生的, 所以说并不是CLR的产物
二. 用法:
a) Async出现在方法的声明上, 任何一个方法添加一个async关键字都不会报错
b) 如果只有awit, 是会报错的
c) Awit必须放在task前面, 必须和async成对出现
d) Awit和async成对出现, 会被编译成状态机
三. 一个简单的示例:
private static async void NoReturn()
{
//主线程执行
Console.WriteLine($"NoReturn Sleep before await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
TaskFactory taskFactory = new TaskFactory();
//主线程启动一个子线程执行
Task task = taskFactory.StartNew(() =>
{
Console.WriteLine($"NoReturn Sleep before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(3000);
Console.WriteLine($"NoReturn Sleep after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
});
await task;//主线程碰到await就返回去执行主线程的其它任务(循环), 而这个方法的下面的代码则不再执行, 等待主线程把其它任务执行完毕, 程序会再次跳回来执行这个方法的下面的其它代码; 但是注意, 再次跳回来的时候, 并不一定是主线程执行, 也有可能是新开一个线程来执行
//这个回调的线程是不确定的:可能是主线程 可能是子线程 也可能是其他线程
Console.WriteLine($"NoReturn Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
} //调用代码: NoReturn();
for (int i = 0; i < 10; i++)
{
Thread.Sleep(300);
Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId} i={i}"); }
四. Await和async的返回值
a) 当使用await和async时, 如果没有返回值, 则应该标明使用Task作为返回值, 下面的代码演示没有返回值的await和async:
private static async Task NoReturnTask()
{
//这里还是主线程的id
Console.WriteLine($"NoReturnTask Sleep before await,ThreadId={Thread.CurrentThread.ManagedThreadId}"); Task task = Task.Run(() =>
{
Console.WriteLine($"NoReturnTask Sleep before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(3000);
Console.WriteLine($"NoReturnTask Sleep after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
});
await task;
Console.WriteLine($"NoReturnTask Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}"); }
b) 当使用await和async时, 如果有返回值, 则应该和Task组成泛型来返回: Task<typeName>, 下面的代码演示有返回值的await和async
private static async Task<long> SumAsync()
{
Console.WriteLine($"SumAsync 111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
long result = 0;
//1. 先启动一个线程, 主线程遇到这里之后, 就会返回去了, 这个子线程开始执行
await Task.Run(() =>
{
for (long i = 0; i < 999999999; i++)
{
result += i;
}
});
return result;
}
c) Awati和async返回值的使用:
Task<long> t = SumAsync();
Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
long lResult = t.Result;//当需要访问result时, 则当前线程必须等待t线程的完成
t.Wait();//等价于上一行
五. 利用await和async像写同步代码一样编写异步执行的代码, 调用方法和第四步的c相同:
/// <summary>
/// 带返回值的Task
/// 要使用返回值就一定要等子线程计算完毕
/// </summary>
/// <returns>async 就只返回long</returns>
private static async Task<long> SumAsync()
{
//在await 和 async 中, 先启动一个线程, 执行完成之后, 接着可以继续awit
//有点类似同步的方式编程, 但是却是异步执行 Console.WriteLine($"SumAsync 111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
long result = 0;
//1. 先启动一个线程, 主线程遇到这里之后, 就会返回去了, 这个子线程开始执行
await Task.Run(() =>
{
for (int k = 0; k < 10; k++)
{
Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(1000);
} for (long i = 0; i < 999999999; i++)
{
result += i;
}
});
//2. 上面的线程执行完成之后, 输出下面这句话; 可以看做这里是其它的动作
Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); //3. 然后继续执行下面这里的线程, 这里又有一个await, 然后主线程又返回去执行其他的
await Task.Run(() =>
{
for (int k = 0; k < 10; k++)
{
Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(1000);
} for (long i = 0; i < 999999999; i++)
{
result += i;
}
});
//4. 这个线程执行完成之后, 开始执行这里输出
Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); //5. 碰到await之后, 开了一个子线程, 然后又返回去了
await Task.Run(() =>
{
for (int k = 0; k < 10; k++)
{
Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(1000);
} for (long i = 0; i < 999999999; i++)
{
result += i;
}
}); Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); return result;
}
六. 总结:
// 1 使用async和await , 能够像写同步代码的方式一样, 达到异步执行的功能
// 2 如果 awit / async 没有返回值, 则使用Task来替代(虽然允许写成void, 但是不要那样做);无返回值时 async Task == async void
// 3 如果有返回值则使用Task<类型> 来处理
// 4 await只能出现在Task前面
// 5 不能单独await
// 6 await 只能放在task前面
// 7 不管你的await和async标识的方法需不需要返回值, 都不推荐void返回, 应该使用Task来代替, 像第二条所说那样, 因为返回Task和Task<T>则能够使用await, 并且可以和Task.WhenAny, Task.WhenAll等方式组合使用, 但是如果返回Void 不行, 则这条线程链就断了
// 8 如果 awit / async 没有返回值, 则使用Task来替代, 如果有返回值则使用Task<类型>来处理
20181110_wait和async的更多相关文章
- [C#] async 的三大返回类型
async 的三大返回类型 序 博主简单数了下自己发布过的异步文章,已经断断续续 8 篇了,这次我想以 async 的返回类型为例,单独谈谈. 异步方法具有三个可让开发人员选择的返回类型:Task&l ...
- async & await 的前世今生(Updated)
async 和 await 出现在C# 5.0之后,给并行编程带来了不少的方便,特别是当在MVC中的Action也变成async之后,有点开始什么都是async的味道了.但是这也给我们编程埋下了一些隐 ...
- [.NET] 利用 async & await 的异步编程
利用 async & await 的异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/5922573.html 目录 异步编程的简介 异 ...
- [.NET] 怎样使用 async & await 一步步将同步代码转换为异步编程
怎样使用 async & await 一步步将同步代码转换为异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/6079707.html ...
- [.NET] 利用 async & await 进行异步 IO 操作
利用 async & await 进行异步 IO 操作 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/6082673.html 序 上次,博主 ...
- [C#] 走进异步编程的世界 - 开始接触 async/await
走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 C# 5.0 引入的 async/await,但在控制台输出示例时经常会采用 C# 6.0 的 $&qu ...
- [译] C# 5.0 中的 Async 和 Await (整理中...)
C# 5.0 中的 Async 和 Await [博主]反骨仔 [本文]http://www.cnblogs.com/liqingwen/p/6069062.html 伴随着 .NET 4.5 和 V ...
- await and async
Most people have already heard about the new “async” and “await” functionality coming in Visual Stud ...
- C# await和async
基础阅读:http://www.cnblogs.com/jesse2013/p/async-and-await.html 答疑阅读:http://www.cnblogs.com/heyuquan/ar ...
随机推荐
- JavaWeb过滤器——登录过滤
一般来说简单且常用的过滤器使用方法,我觉得除了配置字符编码的过滤之外就是登录器的过滤了 登录过滤器的主要过程可以 一句话来概括:首先在登录的时候把指定好的标志放在session中,操作过滤的时候根据s ...
- Axure RP 7.0 注册码
2016.01.25安装可用 Axure RP 7.0 注册码 用户名:axureuser 序列号:8wFfIX7a8hHq6yAy6T8zCz5R0NBKeVxo9IKu+kgKh79FL6 ...
- iOS 阶段学习第三天笔记(运算符)
iOS学习(C语言)知识点整理笔记 1.运算符 一.算术运算符 1)表达式由变量.常量.运算符构成,有确定的类型和值 2)算术运算符包括: +(加),-(减),*(乘),/(除),%(模) 3)算术运 ...
- Struts2开发步骤
第一步:新建we项目 新建名称为“Struts"的web工程,新建方法:File->New->Web Service Project->Profect Name中输入:St ...
- Buildroot构建指南--快速上手与实用技巧
Buildroot官方全英文使用手册的链接是https://buildroot.org/downloads/manual/manual.html,需要知道每一个细节的朋友,可以仔细查阅,这篇文章只是我 ...
- 小程序开发之scroll-view中id不能以数字开头的问题
在实现这样的一个功能时, 调用微信小程序api发现scroll中可以通过id来实现点击菜单栏,屏幕滚动到对应的id位置 但是id不能以数字,汉字类型的 字符串开头(暂发现两种),可能博主比较笨,想 ...
- 【剑指offer】判断一个序列是否是二叉搜索树的后序遍历,C++实现
原创文章,转载请注明出处! 本题牛客网地址 博客文章索引地址 博客文章中代码的github地址 1.题目 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出N ...
- Unity是什么?
Unity是patterns & practices团队开发的一个轻量级.可扩展的依赖注入容器,具有如下的特性: 1. 它提供了创建(或者装配)对象实例的机制,而这些对象实例可能还包含了其它被 ...
- CentOS7 firewalld设置端口
Centos升级到7之后,发现无法使用iptables控制Linuxs的端口,google之后发现Centos 7使用firewalld代替了原来的iptables.下面记录如何使用firewalld ...
- Python递归输出字典所有不同深度的路径
应用场景 假设有这样一个字典结构test_dict = {'a':{'b':{'c':1}},'d':2},test_dict其实可以看作是一种树状结构,其中每个叶子节点深度不一定相同,如果我们希望输 ...