C#异步编程之基于任务的异步模式
http://www.cnblogs.com/afei-24/p/6757361.html该文讲了基于任务的编程,这里再详细介绍一下。
一.延续任务
private async static void CallerWithAsync()
{
string result = await GreetingAsync("Stephanie");
Console.WriteLine(result);
} static Task<string> GreetingAsync(string name)
{
return Task.Run<string>(() =>
{
Thread.Sleep();
return name;
});
} GreetingAsync方法返回一个Task<string>对象。该Task<string>对象包含任务创建的信息,并保存到任务完成。Task类的ContinueWith方法定义了任务完成后就调用的代码。
private static void CallerWithContinuationTask()
{ var t1 = GreetingAsync("Stephanie"); t1.ContinueWith(t =>
{
string result = t.Result;
Console.WriteLine(result);
}); }
由于不使用await,线程不会在方法中等待,会执行完CallerWithContinuationTask()的代码。不会再ContinueWith这里等待,所以需要一个前台线程,不然会关闭所以线程。
二.同步上下文
CallerWithAsync和CallerWithContinuationTask方法在方法的不同阶段使用了不同的线程。
static Task<string> GreetingAsync(string name)
{
return Task.Run<string>(() =>
{
Thread.Sleep();
Console.WriteLine("running greetingasync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
return name;
});
}
private async static void CallerWithAsync()
{
Console.WriteLine("started CallerWithAsync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
string result = await GreetingAsync("Stephanie");
Console.WriteLine(result);
Console.WriteLine("finished GreetingAsync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
} private static void CallerWithContinuationTask()
{
Console.WriteLine("started CallerWithContinuationTask in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId); var t1 = GreetingAsync("Stephanie"); t1.ContinueWith(t =>
{
string result = t.Result;
Console.WriteLine(result);
Console.WriteLine("finished CallerWithContinuationTask in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
}); }
使用async和await关键字,当await完成后,不需要进行任何处理,就能访问UI线程。默认情况下,生成的代码就会把线程转换到拥有同步上下文的线程中。调用异步方法的线程分配给了同步上下文,await完成之后将继续执行。
如果不使用相同的同步上下文,必须调用Task类的ConfigureAwait(false).例如,一个WPF应用程序,其await后面的代码没有任何用到UI元素的代码。在这种情况下,避免切换到同步上下文会执行的更快。
string s1 = await GreetingAsync("Stephanie").ConfigureAwait(false);
三.使用多个异步方法
在一个异步方法里,可以调用一个或多个异步方法。如何编写代码,取决于一个异步方法的结果是否取决于另一个异步方法。
1.按顺序调用异步方法
下面的例子,第第二个异步方法依赖于第一个异步方法的结果,await关键字就很有用。
private async static void MultipleAsyncMethods()
{
string s1 = await GreetingAsync("Stephanie");
string s2 = await GreetingAsync(s1);
Console.WriteLine("Finished both methods.\n Result 1: {0}\n Result 2: {1}", s1, s2);
}
2.使用组合器
如果第二个异步方法独立于第一个,每个异步方法可以都不使用await,而是把每个异步方法的返回结果赋值给Task变量,就会运行的更快。
private async static void MultipleAsyncMethodsWithCombinators1()
{
Task<string> t1 = GreetingAsync("Stephanie");
Task<string> t2 = GreetingAsync("Matthias");
await Task.WhenAll(t1, t2);
Console.WriteLine("Finished both methods.\n Result 1: {0}\n Result 2: {1}", t1.Result, t2.Result);
}
Task.WhenAll组合器可以接受多个同一类型的参数,并返回同一类型的值。
Task.WhenAll是在所有传入方法的任务都完成了才返回Task。
WhenAny是在其中一个传入方法的任务完成了就返回。
Task.WhenAll定义了几个重载版本。如果所有的任务返回相同的类型,那么该类型的数组可用于await返回的结果。
string[] result = await Task.WhenAll(t1, t2);
四.转换异步模式
http://www.cnblogs.com/afei-24/p/6757361.html讲了三种异步编程的模式。
并非所有的.NET Framework类在.NET 4.5中都引入了新的异步方法。还有许多类只提供类BeginXXX和EndXXX方法的异步模式,可以使用TaskFactory类的FromAsync方法,它可以把使用异步模式的方法转换为基于任务的异步模式的方法。
/创建一个委托,并引用同步方法Greeting
private static Func<string, string> greetingInvoker = Greeting; static IAsyncResult BeginGreeting(string name, AsyncCallback callback, object state)
{
return greetingInvoker.BeginInvoke(name, callback, state);
} static string EndGreeting(IAsyncResult ar)
{
return greetingInvoker.EndInvoke(ar);
} //FromAsync方法的前两个参数是委托类型,传入BeginGreeting, EndGreeting的地址。后两个参数是输入的参数和对象状态参数。
private static async void ConvertingAsyncPattern()
{
string r = await Task<string>.Factory.FromAsync<string>(BeginGreeting, EndGreeting, "Angela", null);
Console.WriteLine(r);
}
五.错误处理
如果调用异步方法没有等待,将异步方法放在try/catch中,就不捕获不到异常。
private static void DontHandle()
{
try
{
ThrowAfter(, "first");
// exception is not caught because this method is finished before the exception is thrown
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
} static async Task ThrowAfter(int ms, string message)
{
Console.Write("xxx");
await Task.Delay(ms);
throw new Exception(message);
}
DontHandle方法调用ThrowAfter后,不会在该处等待,会继续执行,不再保持对ThrowAfter方法的引用。
注意:返回void的异步方法永远不会等待.异步方法最好返回一个Task类型。
1.异步方法的异常处理
使用await关键字,将其放在在try/catch中
private static async void HandleOneError()
{
try
{
await ThrowAfter(, "first");
}
catch (Exception ex)
{
Console.WriteLine("handled {0}", ex.Message);
}
}
2.多个异步方法的异常处理
如果按照下面的代码,第二个异常将不会抛出。因为第一个异常已经抛出,直接调到catch块内了。
private static async void StartTwoTasks()
{
try
{
await ThrowAfter(, "first");
await ThrowAfter(, "second"); // the second call is not invoked because the first method throws an exception
}
catch (Exception ex)
{
Console.WriteLine("handled {0}", ex.Message);
}
}
使用Task.WhenAll,不管任务是否抛出异常,都会等到两个任务完成。所以会抛出两个异常。
但是,只能看见传递给Task.WhenAll方法的第一个任务的异常信息,虽然第二个异常会抛出,但不会显示:
private async static void StartTwoTasksParallel()
{
Task t1 = null;
Task t2 = null;
try
{
t1 = ThrowAfter(, "first");
t2 = ThrowAfter(, "second");
await Task.WhenAll(t1, t2);
}
catch (Exception ex)
{
// just display the exception information of the first task that is awaited within WhenAll
Console.WriteLine("handled {0}", ex.Message);
}
}
3.使用AggregateException信息返回显示异常
将Task.WhenAll返回的结果写到一个Task变量中,catch语句只检索到第一个任务的异常,但可以访问外部任务taskResult的Exception属性。Exception属性是AggregateException类型。这个异常类型定义了InnerExceptions属性,它包含了等待中的所有异常的列表。
private static async void ShowAggregatedException()
{
Task taskResult = null;
try
{
Task t1 = ThrowAfter(, "first");
Task t2 = ThrowAfter(, "second");
await (taskResult = Task.WhenAll(t1, t2));
}
catch (Exception ex)
{
// just display the exception information of the first task that is awaited within WhenAll
Console.WriteLine("handled {0}", ex.Message);
foreach (var ex1 in taskResult.Exception.InnerExceptions)
{
Console.WriteLine("inner exception {0} from task {1}", ex1.Message, ex1.Source);
}
}
}
六.取消异步方法
如果后台任务可能运行很长时间,就可能用的取消任务。
取消框架基于协助行为,不是强制性的。一个运行时间很长的任务需要检查自己是否被取消,在这种情况下,它的工作就是清理所有已打开的资源,并结束相关工作。
取消基于CancellationTokenSource类,该类可用于发送取消请求。请求发送给引用CancellationToken类的任务,其中CancellationToken类和CancellationTokenSource相关联。
private CancellationTokenSource cts = new CancellationTokenSource(); //添加一个按钮,用于取消正在运行的任务。使用cts.Cancel();
private void button5_Click(object sender, EventArgs e)
{
if (cts != null)
cts.Cancel();
} private async void button4_Click(object sender, EventArgs e)
{ string s = await AsyncTaskTest();
} //向Task类的Run方法传递CancellationToken参数。但需要检查是否请求了取消操作。
Task<string> AsyncTaskTest()
{
return Task.Run(() =>
{
cts.Token.ThrowIfCancellationRequested();
Thread.Sleep();
return "异步完成";
}
, cts.Token);
}
C#异步编程之基于任务的异步模式的更多相关文章
- 温故知新,CSharp遇见异步编程(Async/Await),聊聊异步编程最佳做法
什么是异步编程(Async/Await) Async/Await本质上是通过编译器实现的语法糖,它让我们能够轻松的写出简洁.易懂.易维护的异步代码. Async/Await是C# 5引入的关键字,用以 ...
- 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换
[源码下载] 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换 作者:webabcd 介绍 ...
- C# 异步编程4 async与await 异步程序开发
随着C#异步程序开发系列的深入,你会发现编写异步程序越发简单.事物的发展就是这样的规律,从简单到复杂再到简单. 在C# 5.0中我们可以通过async与await关键字实现快捷的异步程序开发,如下: ...
- C#中的异步调用及异步设计模式(三)——基于事件的异步模式
四.基于事件的异步模式(设计层面) 基于事件的C#异步编程模式是比IAsyncResult模式更高级的一种异步编程模式,也被用在更多的场合.该异步模式具有以下优点: · ...
- 多线程之异步编程: 经典和最新的异步编程模型,async与await
经典的异步编程模型(IAsyncResult) 最新的异步编程模型(async 和 await) 将 IAsyncInfo 转换成 Task 将 Task 转换成 IAsyncInfo 示例1.使用经 ...
- 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换
经典的异步编程模型(IAsyncResult) 最新的异步编程模型(async 和 await) 将 IAsyncInfo 转换成 Task 将 Task 转换成 IAsyncInfo 示例1.使用经 ...
- C#中的异步调用及异步设计模式(二)——基于 IAsyncResult 的异步设计模式
三.基于 IAsyncResult 的异步设计模式(设计层面) IAsyncResult 异步设计模式通过名为 BeginOperationName 和 EndOperationName 的两个方法来 ...
- 【温故而知新-万花筒】C# 异步编程 逆变 协变 委托 事件 事件参数 迭代 线程、多线程、线程池、后台线程
额基本脱离了2.0 3.5的时代了.在.net 4.0+ 时代.一切都是辣么简单! 参考文档: http://www.cnblogs.com/linzheng/archive/2012/04/11/2 ...
- C#之异步编程
1 异步编程的重要性 C#5.0最重要的改进是提供了更强大的异步编程,C#5.0仅增加两个关键字Async和Await,使用异步编程,方法调用是后台运行(通常在线程和任务的帮助下),并且不会阻塞调用线 ...
随机推荐
- Docker学习笔记_安装和使用nginx
一.软件环境 1.宿主机OS:Win10 64位 2.虚拟机OS:Ubuntu 18.04,虚拟机IP:192.168.8.25 3.Docker安装在虚拟机Ubuntu 18.04上 二.安装过程 ...
- c语言学习笔记 if语句执行流程和关系运算符
回想现实生活中,我们会遇到这样的情况,如果下雨了就带伞上班,如果没下雨就不带伞上班,这是很正常的逻辑.程序是解决生活中的问题的,那么自然在程序中也需要这样的判断,当满足某个条件的时候做一件事情,这种东 ...
- weblogic参数说明
公司有个项目,部署在weblogic8.1上之后,发现比在tomcat下慢很多,经过分析排查,原因是web应用的WEB-INF下的weblogic.xml里的参数设置不合理(使用默认值有时并非最佳值) ...
- 9.hive聚合函数,高级聚合,采样数据
本文主要使用实例对Hive内建的一些聚合函数.分析函数以及采样函数进行比较详细的讲解. 一.基本聚合函数 数据聚合是按照特定条件将数据整合并表达出来,以总结出更多的组信息.Hive包含内建的一些基本聚 ...
- 前端基础 之 Bootstrap框架
浏览目录 Bootstrap介绍 为什么要使用Bootstrap? Bootstrap环境搭建 布局容器 栅格系统 Bootstrap全局样式 一.Bootstrap介绍 Bootstrap是Twit ...
- Entity Framework Tutorial Basics(42):Colored Entity
Colored Entity in Entity Framework 5.0 You can change the color of an entity in the designer so that ...
- (转)基于 WPF + Modern UI 的 公司OA小助手 开发总结
原文地址:http://www.cnblogs.com/rainlam163/p/3365181.html 前言: 距离上一篇博客,整整一个月的时间了.人不能懒下来,必须有个阶段性的总结,算是对我这个 ...
- eclipse中的项目无法在build/classes目录下生成.class字节码
转载 原文链接:https://www.cnblogs.com/iceblow/p/6648715.html 1.首先确定project->Build Automatically是否勾选上: ...
- MongoDB整理笔记の安装及配置
1.官网下载 地址:http://www.mongodb.org/downloads mongodb-linux-x86_64-2.4.9.tgz (目前为止,64位最新版本) 2.解压 切换到下载目 ...
- 微信运动数据抓取(PHP)
“微信运动”能够向朋友分享一个包含有运动数据的网页,网页中就有我们需要的数据.url类似于:http://hw.weixin.qq.com/steprank/step/personal?openid= ...