多线程编程学习笔记——async和await(二)

时间:2023-02-03 14:07:20

接上文 多线程编程学习笔记——async和await(一)

三、   对连续的异步任务使用await操作符

本示例学习如何阅读有多个await方法方法时,程序的实际流程是怎么样的,理解await的异步调用 。

1。示例代码如下。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading; namespace ThreadAsyncDemo
{ class Program
{
static void Main(string[] args)
{

Console.WriteLine(string.Format("----- 对连续的异步任务使用await操作符----"));

            Task t = AsyncWithTPL();
t.Wait();
t = AsyncWithAwait();
t.Wait();
Console.Read();
} static Task AsyncWithTPL()
{
var containerTask = new Task(() =>
{
Task<string> task1 = GetInfoAsync("TPL Task 1"); task1.ContinueWith(task =>
{
Console.WriteLine(task1.Result); Task<string> task2 = GetInfoAsync("TPL Task 2");
task2.ContinueWith(innerTask =>
Console.WriteLine(innerTask.Result), TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.AttachedToParent); task2.ContinueWith(innerTask =>
Console.WriteLine(innerTask.Exception.InnerException), TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.AttachedToParent); }, TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.AttachedToParent);
task1.ContinueWith(task =>
Console.WriteLine(task1.Exception.InnerException), TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.AttachedToParent);
}
);
containerTask.Start();
return containerTask;
}
async static Task AsyncWithAwait()
{
try
{
string result = await GetInfoAsync("Async Task 1");
Console.WriteLine(result);
result = await GetInfoAsync("Async Task 2");
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
} async static Task<string> GetInfoAsync(string name)
{
Console.WriteLine(string.Format("任务 {0} 开始。。。",name));
await Task.Delay(TimeSpan.FromSeconds());
if(name== "TPL Task 2")
throw new Exception(string.Format("{0} 抛出异常信息!", name));
return string.Format(" Task {0} 正在运行在线程 ID={1}上。这个工作线程是否是线程池中的线程:{2}", name,
Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
}
}
}

2.程序运行结果,如下图。

多线程编程学习笔记——async和await(二)

首先,程序运行时会执行两个异步操作。

  1. AsyncWithAwait方法,它看起来跟平常的代码一样,唯一不同之处就是使用了两个await声明。最重要的一点是代码的执行顺序依然是顺序执行的,调用AsyncWithAwait任务的代码只有等 之前的的任务完成 后才会开始执行。当阅读代码时,程序流很清晰,可以看到什么先执行,什么后执行,但是程序如何异步执行呢?首先,它不是一直是异步执行的,只有当使用await,且一个任务已经完成,我们会异步地得 到这个任务的结果。否则 ,当在代码中看到await声明时,通过的行为是代码执行到await代码行时将立即返回,并且剩下的代码将会在一个后续操作任务中运行。因此等待操作结果时并没有阻塞程序执行,这是一个异步调用 。当AsyncWithAwait方法中的代码执行时,除了在main方法中调用 t.wait外,我们可以执行任务其他任务。但是主线程必须等待直到所有的异步操作完成 ,否则 主线程完成后所有运行异步操作的后台线程会停止运行。
  2. AsyncWithTPL方法模仿了AsyncWithAwait的程序流。我们需要一个容器任务来处理所有相互依赖的任务。然后启动主任务,给其加了一组后续操作。当这个任务完成 后,会打印其结果。然后又启动了一个任务,在这个任务完成后会依次运行更多的后续操作。为了测试对异常的处理,当运行第二个任务时故意抛出了一个异常。并打印出异常信息。这组后续操作创建了与第一个方法中一样的程序流。

二、   对并行执行的异步任务使用await操作符

本示例学习如何使用await来并行地运行异步任务,而不采用常规使用顺序执行方式。

1.示例代码如下。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading; namespace ThreadAsyncDemo
{ class Program
{ static void Main(string[] args)
{
Console.WriteLine(string.Format("----- 对并行执行的异步任务使用await操作符----"));
Task t = AsyncProcess();
t.Wait();
Console.Read(); } async static Task AsyncProcess()
{ Task<string> task1 = GetInfoAsync("Task 1",); Task<string> task2 = GetInfoAsync("Task 2",);
string[] results = await Task.WhenAll(task1, task2);
foreach (var item in results)
{
Console.WriteLine(item);
}
} async static Task<string> GetInfoAsync(string name,int second)
{
Console.WriteLine(string.Format("任务 {0} 开始。。。",name)); await Task.Delay(TimeSpan.FromSeconds(second));
//await Task.Run(() => Thread.Sleep(TimeSpan.FromSeconds(second));
return string.Format(" Task {0} 正在运行在线程 ID={1}上。这个工作线程是否是线程池中的线程:{2}", name,
Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
}
}
}

2.程序运行结果,如下图。

多线程编程学习笔记——async和await(二)

在AsyncProcess方法中定义了两个异步任务task1,task2,分别运行3秒和5秒。然后使用Task.WhenAll辅助方式得到了两个任务的运行结果,而且只有在所有底层任务完成之后,才会运行。之后我们等待这个组合任务的结果。5秒后,我们获取所有结果,说明了这些任务是同时运行的。

我们仔细观察会发现,这两个任务假托是被线程池中的同一个工作线程执行的。当我们并行运行任务时怎么可能发生这样的情况呢?我们注释掉GetIntroAsync方法中的await Task.Delay代码 行,并解除对await task.run代码行的注释,然后再次运行程序。

我们会看到这种情况下,两个任务会被不同的工作线程执行。不同之处是task.delay在幕后使用了一个计时器,过程如下:从线程池中获取工作线程,它将等待task.delay方法返回结果。然后task.delay方法启动计时器并指定一段代码,这段代码会在计时器时间到了task.delay方法中指定的秒数后被 调用 ,之后,立即将工作线程返回到线程池中。当计时器事件运行时,又从线程池中任意获取一个可用的工作线程(可能跟上次运行的是同一个工作线程),并运行计时器指定的代码。

当使用task.run方法时,从线程池中获取了一个工作线程并将其阻塞几秒,然后获取了第二个工作线程也将其阻塞。在这种情况下,我们消费了两个工作线程,但是什么事情也没做。如下图。比较两者的不同之处,在于两个task运行在不同的线程上。

多线程编程学习笔记——async和await(二)

多线程编程学习笔记——async和await(二)的更多相关文章

  1. 多线程编程学习笔记——async和await(三)

    接上文 多线程编程学习笔记——async和await(一) 接上文 多线程编程学习笔记——async和await(二) 五.   处理异步操作中的异常 本示例学习如何在异步函数中处理异常,学习如何对多 ...

  2. 多线程编程学习笔记——async和await(一)

    接上文 多线程编程学习笔记——任务并行库(一) 接上文 多线程编程学习笔记——任务并行库(二) 接上文 多线程编程学习笔记——任务并行库(三) 接上文 多线程编程学习笔记——任务并行库(四) 通过前面 ...

  3. 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端

    接上文 多线程编程学习笔记——使用异步IO 二.   编写一个异步的HTTP服务器和客户端 本节展示了如何编写一个简单的异步HTTP服务器. 1.程序代码如下. using System; using ...

  4. 多线程编程学习笔记——使用异步IO(一)

    接上文 多线程编程学习笔记——使用并发集合(一) 接上文 多线程编程学习笔记——使用并发集合(二) 接上文 多线程编程学习笔记——使用并发集合(三) 假设以下场景,如果在客户端运行程序,最的事情之一是 ...

  5. 多线程编程学习笔记——异步调用WCF服务

    接上文 多线程编程学习笔记——使用异步IO 接上文 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端 接上文 多线程编程学习笔记——异步操作数据库 本示例描述了如何创建一个WCF服务,并宿主 ...

  6. 多线程编程学习笔记——使用异步IO

    接上文 多线程编程学习笔记——使用并发集合(一) 接上文 多线程编程学习笔记——使用并发集合(二) 接上文 多线程编程学习笔记——使用并发集合(三) 假设以下场景,如果在客户端运行程序,最的事情之一是 ...

  7. Java多线程编程&lpar;学习笔记&rpar;

    一.说明 周末抽空重新学习了下多线程,为了方便以后查阅,写下学习笔记. 有效利用多线程的关键是理解程序是并发执行而不是串行执行的.例如:程序中有两个子系统需要并发执行,这时候需要利用多线程编程. 通过 ...

  8. &lbrack;Java123&rsqb; JDBC and Multi-Threading 多线程编程学习笔记

    项目实际需求:DB交互使用多线程实现 多线程编程基础:1.5  :( (假设总分10) 计划一个半月从头学习梳理Java多线程编程基础以及Oracle数据库交互相关的多线程实现 学习如何通过代码去验证 ...

  9. python学习笔记 async and await

    用asyncio提供的@asyncio.coroutine可以把一个generator标记为coroutine类型,然后在coroutine内部用yield from调用另一个coroutine实现异 ...

随机推荐

  1. No module named yum错误的解决办法

    今天用yum安装软件的时候出现如下错误: There was a problem importing one of the Python modules required to run yum. Th ...

  2. 关于androidManifest&period;xml的概叙以及intent-filter的详细分析

    AndroidManifest.xml配置文件对于Android应用开发来说是比较细但又很重要的基础知识,本文旨在总结该配置文件中常用到的几个属性,以便日后查阅,至于那些比较细的属性,主要是平时开发比 ...

  3. Class org&period;apache&period;struts2&period;json&period;JSONWriter can not access a member of

    异常形式: Class org.apache.struts2.json.JSONWriter can not access a member of * 或是 Class com.googlecode. ...

  4. Python爬虫处理抓取数据中文乱码问题

    乱码原因:因为你的文件声明为utf-8,并且也应该是用utf-8的编码保存的源文件.但是windows的本地默认编码是cp936,也就是gbk编码,所以在控制台直接打印utf-8的字符串当然是乱码了. ...

  5. WPF MVVM 架构 Step By Step&lpar;6&rpar;(把actions从view model解耦)

    到现在为止,我们创建了一个简单的MVVM的例子,包含了实现了的属性和命令.我们现在有这样一个包含了例如textbox类似的输入元素的视图,textbox用绑定来和view model联系,像点击but ...

  6. Raid 5数据恢复原理以及raid 5数据恢复实际操作案例

    Raid 5数据恢复算法原理 要理解 raid 5数据恢复原理首先要先认识raid5,"分布式奇偶校验的独立磁盘结构"也就是我们称之为的raid 5数据恢复有一个概念需要理解,也就 ...

  7. python中两种方法实现二分法查找,细致分析二分法查找算法

    之前分析了好多排序算法,可难理解了呢!!(泣不成声)这次我要把二分查找总结一下,这个算法不算难度特别大,欢迎大家参考借鉴我不喜欢太官方的定义,太晦涩的语言,让人看了就头晕.我希望加入我自己的理解,能帮 ...

  8. 08-Python入门学习-文件与函数

    一.文件 1.控制文件内指针的移动 文件内指针移动,只有t模式下的read(n),n代表的字符的个数除此以外文件内指针的移动都是以字节为单位 with open('a.txt',mode='rt',e ...

  9. script 修改 plist遇到的问题

    一个sh脚本每次build的时候动态修改info.plist文件 达到动态更改版本号的目的 但是估计是因为缓存的缘故 每次只有clean之后再运行才会修改成功 看script执行的log 好像是先修改 ...

  10. &lbrack;Big Data - Kafka&rsqb; Kafka设计解析(三):Kafka High Availability (下)

    Kafka是由LinkedIn开发的一个分布式的消息系统,使用Scala编写,它以可水平扩展和高吞吐率而被广泛使用.目前越来越多的开源分布式处理系统如Cloudera.Apache Storm.Spa ...