C#多线程编程(2)-- async,await基本用法
上一章我简单介绍了异步编程的基本方法,推荐使用的方式是Task。Task是对线程池的封装,并且可以对Task使用async和await关键字。这两个关键字的使用非常简单,那么这两个关键字究竟起什么作用?工作原理是怎样的?本文就来简单解释。
本系列是我读《CLR via C#》的总结,但是书中关于async和await关键字的讲解不是很多。其中28.3小节通过简单例子以及IL反编译的方式,讲解了编译器如何将异步函数编译成状态机,虽然反编译出的代码中作者添加了大量的注释,无奈本人能力有限,很多底层代码不能很好的理解,因此我通过小例子的方式反复的尝试,加上书中的讲解,我想我已经基本掌握了async和await的使用方式和基本原理。若您有兴趣了解底层代码,可以找来《CLR via C#》的28.2和28.3章节来读一读。
上一章节已经讲了,当你想要利用另一个线程来执行一段程序,推荐的方式是Task,我们看个例子:
public async void RunAsync(){
var t = await Task.Run(() =>
{
//模拟其他操作
Thread.Sleep();
return "task finished";
});
Console.WriteLine(t);
}
运行代码,可以看到程序在大约2秒后,控制台会打印出"task finished",且在这过程中,主线程没有被Sleep(阻塞),RunAsync后面的方法可以继续执行,如
static void Main(string[] args) {
RunAsync();
Console.WriteLine("");
Console.Read();
}
控制台会先显示123,过大约2秒后,显示task finished。程序在执行RunAsync()后,跳过了该方法,直接执行了Console.WriteLine("123")。可以看到RunAsync方法的签名中添加了async关键字,在Task.Run()前面添加了await关键字,这两个关键字的作用是表示RunAsync方法在执行到await关键字后,会将该方法的其余部分封装成一个委托,该委托会在Task.Run()返回的task执行完成后,执行该委托(具体编译器如何将该方法转换成状态机,并在任务结束后,再继续执行该委托,可以看《CLR via C#》的28.3章节)。
public async void RunAsync(){
//其他操作
//当遇到await,会将后面的程序封装成一个委托
var t = await Task.Run(() =>
{
Thread.Sleep();
return "task finished";
});
//这里往后的代码被封装成委托,当t.IsComplete后,才会被执行
//其他操作
Console.WriteLine(t);
}
关键字async表明该方法是一个异步方法,await关键字只允许在标有async的方法中使用。当异步方法具有返回值时,调用该异步方法的函数也要添加async关键字,并在调用方法处添加await,不然会造成异步失效。
static void Main(string[] args){
Console.WriteLine(RunAsync().Result);
Console.WriteLine("Async Run");
Console.Read();
}
public static async Task<string> RunAsync(){
return await Task.Run(() =>
{
Thread.Sleep();
return "task finished";
});
}
运行,程序在等待大约2秒后,显示task finished,然后再显示Async Run,这是因为虽然RunAsync方法异步返回,但是主线程一直在等待RunAsync的结果,除此之外什么也不干,这样当然是不好。
static void Main(string[] args){
TestAsync();
Console.WriteLine("Async Run");
Console.Read();
}
public static async Task<string> RunAsync(){
return await Task.Run(() =>
{
Thread.Sleep();
return "task finished";
});
}
public static async void TestAsync(){
Console.WriteLine(await RunAsync());
}
Main函数无法添加async关键字,因此我用TestAsync方法包装了一下,可以看到添加了await 和async关键字后,程序会先出现Async Run,然后是task finished。即在异步函数的调用中,若函数包含返回值,则应通过添加await的方式调用异步函数,这样可以做到接着异步,而不是半途而废的异步。
在循环中也可以添加await关键字
static void Main(string[] args)
{
TestAsync();
Console.WriteLine("Async Run");
Console.Read();
}
public static async Task<string> RunAsync()
{
return await Task.Run(() =>
{
Thread.Sleep();
return "task finished";
});
}
public static async void TestAsync()
{
for (int i = ; i < ; i++)
{
Console.WriteLine(await RunAsync() + i);
}
}
上述例子会以你希望的那样,先显示Async Run,然后依次打印task finished0 - task finished4,且每次打印间歇大约2秒。
以上就是Task与 async 和 await 关键字的使用以及基本原理。使用await关键字,该关键字之后的逻辑都会被封装到一个委托,等到任务执行结束后,再调用当前线程继续执行该委托。那么能够调用当前线程,也应该有方法当任务执行结束后,继续调用线程池来执行方法。该部分C#多线程编程(3)会有讲解。欢迎有问题的小伙伴和我在评论区交流。
C#多线程编程(2)-- async,await基本用法的更多相关文章
- 基于任务的异步编程(Task,async,await)
这节讲一下比较高级的异步编程用法Task,以及两个异步关键字async和await. Task是在C#5.0推出的语法,它是基于任务的异步编程语法,是对Thread的升级,也提供了很多API,先看一下 ...
- C# 异步编程(async&await)
同步:同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去 异步:异步是指进程不需要一直等下去,而是继续执行下面的操作 ...
- async & await 的用法
async 和 await 出现在C# 5.0之后,给并行编程带来了不少的方便,特别是当在MVC中的Action也变成async之后,有点开始什么都是async的味道了.但是这也给我们 编程埋下了一些 ...
- 异步编程(async&await)
前言 本来这篇文章上个月就该发布了,但是因为忙 QuarkDoc 一直没有时间整理,所以耽搁到今天,现在回归正轨. C# 5.0 虽然只引入了2个新关键词:async和await.然而它大大简化了异步 ...
- 学习迭代器实现C#异步编程——仿async/await(一)
.NET 4.5的async/await真是个神奇的东西,巧妙异常以致我不禁对其实现充满好奇,但一直难以窥探其门径.不意间读了此篇强文<Asynchronous Programming in C ...
- python3.6以上 asyncio模块的异步编程模型 async await语法
这是python3.6以上版本的用法,本例是python3.7.2编写使用asyncio模块的异步编程模型,生产这消费者,异步生产,用sleep来代替IO等待使用async和await语法来进行描述a ...
- C# 异步操作 async await 的用法
1. async与 await 成对出现 async 在方法前使用 ,方法体面面用 await . 2. 使用async 和await定义异步方法不会创建新线程. 3.await 后面一定是一个扫行 ...
- async await的用法
const fs = require('fs'); const readFile = function (fileName) { return new Promise(function (resolv ...
- c# 异步编程demo (async await)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.W ...
- promise和async/await的用法
promise和async都是做异步处理的, 使异步转为同步 1.promise 它和Promise诞生的目的都是为了解决“回调地狱”, promise使用方法: <button @click= ...
随机推荐
- TensorFlow实战之实现自编码器过程
关于本文说明,已同步本人另外一个博客地址位于http://blog.csdn.net/qq_37608890,详见http://blog.csdn.net/qq_37608890/article/de ...
- 【Unity3D技术文档翻译】第1.4篇 AssetBundle 依赖关系
上一章:[Unity3D技术文档翻译]第1.3篇 创建 AssetBundles 本章原文所在章节:[Unity Manual]→[Working in Unity]→[Advanced Develo ...
- 通过实例介绍持续集成的应用--基于Jenkins
1.测试工程师为什么要掌握持续集成 一个程序员如果想发布一个产品,他需要编码.编译.测试,发布的过程.对于一个企业来说,如果也想发布一个产品的话,同样的也是需要上述的过程,区别在于企业要发布的产品的需 ...
- Java经典编程题50道之五
利用条件运算符的嵌套来完成此题:学习成绩>=90分的同学用A表示,60-89分之间的用B表示,60分以下的用C表示. public class Example05 { public static ...
- java5 - 数组与排序算法
数组是什么? 一.一维数组 1 声明与定义的区别 一般的情况下我们常常这样叙述, 把建立空间的声明称之为"定义", 而把不需要建立存储空间称之为"声明". 很明 ...
- Yii小部件
小部件 Yii提供了一套数据小部件widgets,这些小部件可以用于显示数据. DetailView小部件用于显示一条记录数据. ListView和GridView小部件能够用于显示一个拥有分页.排序 ...
- Office 365 共享链接直接进入编辑
首先在Word online共享文档(不多赘述) 但这个链接打开的是预览视图,要点击右上角的"在浏览器中编辑"才能真正编辑. 但是很多情况都是没必要进入这个预览界面再编辑的.这多点 ...
- Zookeeper笔记3——原理及其安装使用
Zookeeper到底能干什么? 1.配置管理:这个好理解.分布式系统都有好多机器,Zookeeper提供了这样的一种服务:一种集中管理配置的方法,我们在这个集中的地方修改了配置,所有对这个配置感兴趣 ...
- 电脑太卡怎么解决-IT33
首先我们看一下引起电脑卡顿的原因有哪些: 1. 电脑可能感染木马病毒. 2. 硬盘使用时间过长,硬盘有坏道. 3. 软件开太多导致内存不足. 4. 电脑磁盘中冗余或者碎片过多. 5. ...
- ubuntu16.04卸载软件
root@test:/# dpkg -l | grep cobbler root@test:/# sudo dpkg --purge cobbler