[C#] 走进异步编程的世界 - 剖析异步方法(上)
走进异步编程的世界 - 剖析异步方法(上)
序
这是上篇《走进异步编程的世界 - 开始接触 async/await 异步编程》(入门)的第二章内容,主要是与大家共同深入探讨下异步方法。
本文要求了解委托的使用。
目录
介绍异步方法
图1 异步方法的简单结构图
关于 async 关键字:
①在返回类型之前包含 async 关键字
②它只是标识该方法包含一个或多个 await 表达式,即,它本身不创建异步操作。
③它是上下文关键字,即可作为变量名。
现在先来简单分析一下这三种返回值类型:void、Task 和 Task<T>
(1)Task<T>:调用方法要从调用中获取一个 T 类型的值,异步方法的返回类型就必须是Task<T>。调用方法从 Task 的 Result 属性获取的就是 T 类型的值。
private static void Main(string[] args)
{
Task<int> t = Calculator.AddAsync(, ); //一直在干活 Console.WriteLine($"result: {t.Result}"); Console.Read();
}
Program.cs
internal class Calculator
{
private static int Add(int n, int m)
{
return n + m;
} public static async Task<int> AddAsync(int n, int m)
{
int val = await Task.Run(() => Add(n, m)); return val;
}
}

图2

图3
(2)Task:调用方法不需要从异步方法中取返回值,但是希望检查异步方法的状态,那么可以选择可以返回 Task 类型的对象。不过,就算异步方法中包含 return 语句,也不会返回任何东西。
private static void Main(string[] args)
{
Task t = Calculator.AddAsync(, ); //一直在干活 t.Wait();
Console.WriteLine("AddAsync 方法执行完成"); Console.Read();
}
Program.cs
internal class Calculator
{
private static int Add(int n, int m)
{
return n + m;
} public static async Task AddAsync(int n, int m)
{
int val = await Task.Run(() => Add(n, m));
Console.WriteLine($"Result: {val}");
}
}

图4

图5
(3)void:调用方法执行异步方法,但又不需要做进一步的交互。
private static void Main(string[] args)
{
Calculator.AddAsync(, ); //一直在干活 Thread.Sleep(); //挂起1秒钟
Console.WriteLine("AddAsync 方法执行完成"); Console.Read();
}
Program.cs
internal class Calculator
{
private static int Add(int n, int m)
{
return n + m;
} public static async void AddAsync(int n, int m)
{
int val = await Task.Run(() => Add(n, m));
Console.WriteLine($"Result: {val}");
}
}
Calculator.cs

图6

图7
一、控制流


二、await 表达式
await 表达式指定了一个异步执行的任务。默认情况,该任务在当前线程异步执行。
每一个任务就是一个 awaitable 类的实例。awaitable 类型指包含 GetAwaiter() 方法的类型。
实际上,你并不需要构建自己的 awaitable,一般只需要使用 Task 类,它就是 awaitable。
最简单的方式是在方法中使用 Task.Run() 来创建一个 Task。【注意】它是在不同的线程上执行方法。
让我们一起来看看示例。
internal class Program
{
private static void Main(string[] args)
{
var t = Do.GetGuidAsync();
t.Wait(); Console.Read();
} private class Do
{
/// <summary>
/// 获取 Guid
/// </summary>
/// <returns></returns>
private static Guid GetGuid() //与Func<Guid> 兼容
{
return Guid.NewGuid();
} /// <summary>
/// 异步获取 Guid
/// </summary>
/// <returns></returns>
public static async Task GetGuidAsync()
{
var myFunc = new Func<Guid>(GetGuid);
var t1 = await Task.Run(myFunc); var t2 = await Task.Run(new Func<Guid>(GetGuid)); var t3 = await Task.Run(() => GetGuid()); var t4 = await Task.Run(() => Guid.NewGuid()); Console.WriteLine($"t1: {t1}");
Console.WriteLine($"t2: {t2}");
Console.WriteLine($"t3: {t3}");
Console.WriteLine($"t4: {t4}");
}
}
}

图2-1

图2-2
上面 4 个 Task.Run() 都是采用了 Task Run(Func<TReturn> func) 形式来直接或间接调用 Guid.NewGuid()。
Task.Run() 支持 4 中不同的委托类型所表示的方法:Action、Func<TResult>、Func<Task> 和 Func<Task<TResult>>
internal class Program
{
private static void Main(string[] args)
{
var t = Do.GetGuidAsync();
t.Wait(); Console.Read();
} private class Do
{
public static async Task GetGuidAsync()
{
await Task.Run(() => { Console.WriteLine(Guid.NewGuid()); }); //Action Console.WriteLine(await Task.Run(() => Guid.NewGuid())); //Func<TResult> await Task.Run(() => Task.Run(() => { Console.WriteLine(Guid.NewGuid()); })); //Func<Task> Console.WriteLine(await Task.Run(() => Task.Run(() => Guid.NewGuid()))); //Func<Task<TResult>>
}
}
}

图2-3 Task.Run() 方法的重载
三、How 取消异步操作
CancellationToken 和 CancellationTokenSource 这两个类允许你终止执行异步方法。
(1)CancellationToken 对象包含任务是否被取消的信息;如果该对象的属性 IsCancellationRequested 为 true,任务需停止操作并返回;该对象操作是不可逆的,且只能使用(修改)一次,即该对象内的 IsCancellationRequested 属性被设置后,就不能改动。
(2)CancellationTokenSource 可创建 CancellationToken 对象,调用 CancellationTokenSource 对象的 Cancel 方法,会使该对象的 CancellationToken 属性 IsCancellationRequested 设置为 true。
【注意】调用 CancellationTokenSource 对象的 Cancel 方法,并不会执行取消操作,而是会将该对象的 CancellationToken 属性 IsCancellationRequested 设置为 true。
示例
internal class Program
{
private static void Main(string[] args)
{
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token; var t = Do.ExecuteAsync(token); //Thread.Sleep(3000); //挂起 3 秒
//source.Cancel(); //传达取消请求 t.Wait(token); //等待任务执行完成
Console.WriteLine($"{nameof(token.IsCancellationRequested)}: {token.IsCancellationRequested}"); Console.Read();
} } internal class Do
{
/// <summary>
/// 异步执行
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public static async Task ExecuteAsync(CancellationToken token)
{
if (token.IsCancellationRequested)
{
return;
} await Task.Run(() => CircleOutput(token), token);
} /// <summary>
/// 循环输出
/// </summary>
/// <param name="token"></param>
private static void CircleOutput(CancellationToken token)
{
Console.WriteLine($"{nameof(CircleOutput)} 方法开始调用:"); const int num = ;
for (var i = ; i < num; i++)
{
if (token.IsCancellationRequested) //监控 CancellationToken
{
return;
} Console.WriteLine($"{i + 1}/{num} 完成");
Thread.Sleep();
}
}
}

图3-1

图3-2 注释两行代码

图3-3:图3-1和图3-2的执行结果(注释两行代码)
上图是不调用 Cancel() 方法的结果图,不会取消任务的执行。
下图在 3 秒后调用 Cancel() 方法取消任务的执行:

图3-4:去掉注释

图3-5:图3-1和图3-4的执行结果(去掉注释)
小结
- 介绍异步方法的语法、三种不同的返回值类型(void、Task 和 Task<T>)和控制流程等。
- 简单常用的异步执行方式:Task.Run()。【注意】它是在不同的线程上执行方法。
- 如何取消异步操作。
传送门
补充篇:《走进异步编程的世界 - 剖析异步方法(下)》
GUI 篇:《走进异步编程的世界 - 在 GUI 中执行异步操作》
原文链接:http://www.cnblogs.com/liqingwen/p/5844095.html
【参考】《Illustrated C# 2012》
[C#] 走进异步编程的世界 - 剖析异步方法(上)的更多相关文章
- [C#] 走进异步编程的世界 - 剖析异步方法(下)
走进异步编程的世界 - 剖析异步方法(下) 序 感谢大家的支持,这是昨天发布<走进异步编程的世界 - 剖析异步方法(上)>的补充篇. 目录 异常处理 在调用方法中同步等待任务 在异步方法中 ...
- [C#] 走进异步编程的世界 - 开始接触 async/await
走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 C# 5.0 引入的 async/await,但在控制台输出示例时经常会采用 C# 6.0 的 $&qu ...
- [C#] 走进异步编程的世界 - 在 GUI 中执行异步操作
走进异步编程的世界 - 在 GUI 中执行异步操作 [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5877042.html 序 这是继<开始接 ...
- 走进异步编程的世界 - 开始接触 async/await(转)
序 这是学习异步编程的入门篇. 涉及 C# 5.0 引入的 async/await,但在控制台输出示例时经常会采用 C# 6.0 的 $"" 来拼接字符串,相当于string.Fo ...
- 走进异步编程的世界 - 在 GUI 中执行异步操作
转载:https://www.cnblogs.com/liqingwen/p/5877042.html 走进异步编程的世界 - 在 GUI 中执行异步操作 [博主]反骨仔 [原文地址]http://w ...
- [C#] 走进异步编程的世界 - 开始接触 async/await(转)
原文链接:http://www.cnblogs.com/liqingwen/p/5831951.html 走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 ...
- 走进异步编程的世界 - 开始接触 async/await
[C#] 走进异步编程的世界 - 开始接触 async/await 走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 C# 5.0 引入的 async ...
- 走进异步编程的世界--async/await项目使用实战
起因:今天要做一个定时器任务:五分钟查询一次数据库发现超时未支付的订单数据将其状态改为已经关闭(数据量大约100条的情况) 开始未使用异步: public void SelfCloseGpPayOrd ...
- javascript异步编程方案汇总剖析
code[class*="language-"] { padding: .1em; border-radius: .3em; white-space: normal; backgr ...
随机推荐
- servlet文件下载
创建web工程servlet,新建DownloadServlet.java package com.xmyself.servlet; import java.io.File; import java. ...
- TODO:GitHub创建组织的步骤
TODO:GitHub创建组织的步骤 使用GitHub进行团队合作,写这个步骤主要作用是为了OneTODO作为一个团队组织进行代码的分享,让更多人来参与. 使用帐号.密码登录GitHub 2.右上角加 ...
- 6.DNS公司PC访问外网的设置 + 主DNS服务器和辅助DNS服务器的配置
网站部署之~Windows Server | 本地部署 http://www.cnblogs.com/dunitian/p/4822808.html#iis DNS服务器部署不清楚的可以看上一篇:ht ...
- 如何创建Vim Dotfile?
Dotfile是电脑系统里的隐藏文件,它是专门给更高级的用户,如开发者.程序员或工程师使用的,让他们用来调整系统.如何创建Vim-Dotfile? 可以参考以下步骤: 1. 首先,你要检查一下.vim ...
- lua执行字节码的过程介绍
前面一篇文章中介绍了lua给下面代码生成最终的字节码的整个过程,这次我们来看看lua vm执行这些字节码的过程. foo = "bar" local a, b = "a& ...
- MVC Core 网站开发(Ninesky) 2、栏目
栏目是网站的常用功能,按照惯例栏目分常规栏目,单页栏目,链接栏目三种类型,这次主要做添加栏目控制器和栏目模型两个内容,控制器这里会用到特性路由,模型放入业务逻辑层中(网站计划分数据访问.业务逻辑和We ...
- 协议森林16 小美的桌号(DHCP协议)
作者:Vamei 出处:http://www.cnblogs.com/vamei 转载请先与我联系. DHCP协议用于动态的配置电脑的网络相关参数,如主机的IP地址,路由器出口地址.DNS域名服务器地 ...
- 从零开始编写自己的C#框架(28)——建模、架构与框架
文章写到这里,我一直在犹豫是继续写针对中小型框架的设计还是写些框架设计上的进阶方面的内容?对于中小型系统来说,只要将前面的内容进行一下细化,写上二三十章具体开发上的细节,来说明这个通用框架怎么开发的就 ...
- nodejs模块发布及命令行程序开发
前置技能 npm工具为nodejs提供了一个模块和管理程序模块依赖的机制,当我们希望把模块贡献出去给他人使用时,可以把我们的程序发布到npm提供的公共仓库中,为了方便模块的管理,npm规定要使用一个叫 ...
- [C#] 剖析 AssemblyInfo.cs - 了解常用的特性 Attribute
剖析 AssemblyInfo.cs - 了解常用的特性 Attribute [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5944391.html 序 ...