并发系列64章(异步编程二)第三章

前言

是在第二章基础上续写的,主要是完结第二章例子部分。
请看下面几个例子,感受一下。

报告进度

不管我们完任何app,每次更新的时候都能看到进度条。

而我们知道ui界面更新,一般来说是和更新程序异步的,但是更新程序又要通知ui进度。

代码:

public class Program
{
	static double percentComplete = 0;
	static void Main(string[] args)
	{
		doit();
		Console.ReadKey();
	}

   public static void DoLoop()
	{
		Task.Run(() =>
		{
			for (var i = 1; i <= 100000; i++)
			{
				setPercent(i/1000);
				Console.WriteLine(i);
			}
			setPercent(101);
		});
	}

	public async static void doit()
	{
		var pregress = CallProcessTask();
		var task=MyMethodAsync(pregress);
		DoLoop();
		await task;

	}

	public static void setPercent(int percent)
	{
		percentComplete = percent;
	}

	public static Progress<double> CallProcessTask()
	{
		var progress = new Progress<double>();
		progress.ProgressChanged += (sender, args) =>
		 {
			 //在这里做一些进度变化,显示在ui上。
			 Console.WriteLine("process:"+args);
		 };
		return progress;
	}

	public static Task MyMethodAsync(IProgress<double> progress=null)
	{
		  var task= Task.Run(() =>
		 {
			 while (percentComplete <= 100)
			 {
				 if (progress != null)
				 {
					 Console.WriteLine("查看进度:" + percentComplete);
					 progress.Report(percentComplete);
				 }
			 }
		 });
		return task;
	}
}

上面我想做的事,一个异步的事件——DoLoop。

可能初学者,很喜欢用async 和 await ,可能会认为没有async 和 await的就不是异步事件。

async和 await的存在的作用就在于等待当前异步事件完成,如果没有这个需求,那么你为什么要写呢?

MyMethodAsync 是另一个异步事件,里面做的事监听当前进度。

CallProcessTask是构造一个progress,并写下委托,监听percentComplete的改变。

等待一组任务完成

static void Main(string[] args)
{
	int[] result = DoAll().Result;
	Console.ReadKey();
}

public static async Task<int[]> DoAll()
{
	Task<int> task1 = Task.FromResult(1);
	Task<int> task2 = Task.FromResult(2);
	Task<int> task3 = Task.FromResult(3);
	int[] result=await Task.WhenAll<int>(task1, task2, task3);
	return result;
}

WhenAll 是一个新的task,管理一组Task。监听一组task进度,当全部的task结束,这个task也结束。

使用await的时候,但是当有一个whenall 管理的task果然有多个task失败,那么只会报一个错误。

而使用whenall,我们的需求是要全部成功,要是有一个不成功那么也应该是失败的。所以我们只要截获一个错误是正确的,系统也是这么做的。

下面是截获代码:

public static async Task<int[]> DoAll()
{
	Task<int> task1 = Task.FromResult(1);
	Task<int> task2 = Task.FromResult(2);
	Task<int> task3 = Task.FromResult(3);

	Task<int[]> Alltasks = Task.WhenAll<int>(task1, task2, task3);
	try
	{
	   var result=await Alltasks;
		return result;
	}
	catch
	{
		AggregateException allException = Alltasks.Exception;
		// 处理错误
	}
	return null;
}

等待任意一个任务完成

为啥会有这种需求?可能你觉得我们每次访问的时候都是对一条url,比如说我们访问百度,那么我们不就是访问www.baidu.com。

但是呢,有几个运营服务商,做的相同的业务,都是免费的,但是公司保险起见呢,一起调用,为了确保在不同地域的请求稳定。

static void Main(string[] args)
{
	var result = DoAny(‘www.baidu.com‘,‘www.baidu.com‘).Result;
	Console.ReadKey();
}

public static async Task<byte[]> DoAny(string urlA,string urlB)
{
	var httpClient = new HttpClient();
	Task<Byte[]> DownLoadTaskA = httpClient.GetByteArrayAsync(urlA);
	Task<Byte[]> DownLoadTaskB = httpClient.GetByteArrayAsync(urlB);
	var completedTask =await Task.WhenAny<byte[]>(DownLoadTaskA, DownLoadTaskB);
	return await completedTask;
}

这里值得关注的是为什么有两个await:

var completedTask =await Task.WhenAny<byte[]>(DownLoadTaskA, DownLoadTaskB);

return await completedTask;

因为创建WhenAny 的Task是异步的,而创建 whenAll 的Task 是同步的。

值得注意的是whenAny 当一个任务完成时,那么会返回这个Task。其他任务依然还是在执行,需要考虑的是中断一个task更好,还是直接让他运行完更好。这是需要考虑的地方。

任务完成后处理

比如说有3个任务,我希望只要完成任意一个任务完成后马上接下来完成它的后续任务。

如果我这样写的话:

static void Main(string[] args)
{
	ProcessTasksAsyns();
	Console.ReadKey();
}

public static async Task ProcessTasksAsyns()
{
	Task<int> TaskA = DelayAndReturnAsync(2);
	Task<int> TaskB = DelayAndReturnAsync(3);
	Task<int> TaskC = DelayAndReturnAsync(1);
	Task<int>[] tasks = new[] { TaskA, TaskB, TaskC };
	foreach (var task in tasks)
	{
		var result = await task;
		Console.WriteLine("后续执行:"+result);
	}
}

static async Task<int> DelayAndReturnAsync(int val)
{
	await Task.Delay(TimeSpan.FromSeconds(val));
	Console.WriteLine(val);
	return val;
}

但是得到的却是这样的结果。

这个结果显示Task 完成的顺序是 1 ,2,3秒。

但是执行后续的顺序是await的顺序,也就是2,3,1.

解决方案是将3个任务,分别放在另外3个任务中执行。

static void Main(string[] args)
{
	ProcessTasksAsyns();
	Console.ReadKey();
}

public static async Task ProcessTasksAsyns()
{
	Task<int> TaskA = DelayAndReturnAsync(2);
	Task<int> TaskB = DelayAndReturnAsync(3);
	Task<int> TaskC = DelayAndReturnAsync(1);
	Task<int>[] tasks = new[] { TaskA, TaskB, TaskC };
	var processingTasks = tasks.Select(async t =>
	{
		var result = await t;
		Trace.WriteLine(result);
	});
	await Task.WhenAll(processingTasks);
}

static async Task<int> DelayAndReturnAsync(int val)
{
	await Task.Delay(TimeSpan.FromSeconds(val));
	Console.WriteLine(val);
	return val;
}

当然后面会介绍到其他方法,但是这个解释了,如果去实现这种需求。

原文地址:https://www.cnblogs.com/mengcheng9300/p/12661742.html

时间: 2024-10-13 02:03:35

并发系列64章(异步编程二)第三章的相关文章

第一、二、三章读后感

读了第一.二.三章,我认为编写程序不是这么简单的事情,对程序有了新的看法,以前认为程序只是一行行的代码,只要边写出来能运行就可以了.可是现在觉得,一个好的软件应该有合理的软件架构.设计和实现,还要有各种文件和数据来描述各个程序文件之间的依赖关系.编译参数.链接参数等等,这些都是软件构建的过程,远不是之前想的只是把代码打出来就可以了.编写程序就像起一栋高楼大厦,在编写完代码之后,还要对程序进行更进一步的检查,查看有没有多余的可以改善的地方,是整个程序更加完善.我想,作为一名软件工程专业的学生,我们

并发系列64章(异步编程)第二章

前言 异步编程的概念我在第一章概要的时候,提及了.在此再次简略概要一次. 它采用future模式或者回调模式机制,以避免产生不必要的线程. 异步编程测试的标准 在第一个写这个的原因,是因为测试可能比开发重要.因为在开发一个项目的时候呢?有一个自动化高效精准测试,决定了上线是否稳定.因为程序出bug测试出来可以改,方案不行换方案,但是测试不行上线了.这时候面临的问题就比较大,因为这时候产生了数据. 比如说 app 一张表的设计不合理,在自动化测试中没有体现出来,那么你要更换表的时候就显得异常困难,

异步编程(二)

3.TAP 基于任务的异步编程 1..NET4.0 引入了Task任务,Task的使用 Task task = new Task(()=> { for (int i = 0; i < 1000; i++) { Console.WriteLine("task run"); } }); task.Start(); 这是简单的启动任务:下面是task的一些版本 public Task(Action action); public Task(Action action, Cance

【读书笔记】C#高级编程 第十三章 异步编程

(一)异步编程的重要性 使用异步编程,方法调用是在后台运行(通常在线程或任务的帮助下),并不会阻塞调用线程.有3中不同的异步编程模式:异步模式.基于事件的异步模式和新增加的基于任务的异步模式(TAP,可利用async和await关键字来实现). (二)异步模式 1.C#1的APM 异步编程模型(Asynchronous Programming Model). 2.C#2的EAP 基于事件的异步模式(Event-based Asynchronous Pattern). 3.TAP 基于任务的异步模

《构建之法》第一、二、三章读后感

第一章系统地告诉了我们什么是软件,也就是软件=程序+软件工程,软件工程是怎样的一个存在,包括软件的种类和性质,都系统地分析给我们,更是强调了一个工程团队对软件工程的重要性,同时也给我们指出了某些软件会出现的问题,比如说会有BUG,给我们介绍了当遇到这些问题的时候需要怎样去解决问题和修正BUG,完成客户给我们的要求.总的来说,第一章就是带我们走进了软件工程的线索. 第二章叫做个人技术和流程,在这一章中我看到了程序执行过程中耗时最多的三个函数,三个函数加起来占用了整个程序的84%的时间,并给我们分析

《集体智慧编程》 第三章 发现群组 笔记儿

啦啦啦聚类算法~ 我刚看到这一章的时候内心是崩溃的,许多傻瓜软件点一下鼠标就能完成的事儿,到书里这一章需要许多行代码来完成,也说明了,学数据挖掘,算法real重要.. 本章需要安装: feedparser(第二章安装pydelicious已经安装过了,pip install即可) BeautifulSoup,我也不记得自己是怎么装上的了,据说可以easy_install,大家试一试. PIL,下载地址:http://pythonware.com/products/pil/ 还涉及到一些正则表达式

Jquery的一、二、三章的笔记

第一章:Jquery的基础 JQuery - 是一个JavaScript的框架(函数库) 一.Jquery的使用 1.下载Jquery框架:http://jquery.com 2.在页面引用jquery-x.x.x.js文件 <script type="text/javascript" src="js/jquery-1.7.2.js"></script> 3.使用 二.第一个Jquery程序$() $(document).ready(func

Python编程入门-第三章 编写程序 -学习笔记

第三章 编写程序 1.编辑源程序.运行程序 可通过IDLE中File>New File新建一个文本以编辑源程序,编辑完成可通过Run>Run Module(或者F5快捷键)来运行程序.Python源文件都以.py格式存储. 2.从命令行运行程序 除了上述利用IDLE的集成功能运行程序的方式外,当然也可以通过命令行运行程序,命令格式为:python ‘源文件名称.py’. 3.编译源代码 当运行py格式文件时,Python会自动创建相应的.pyc文件,该文件包含编译后的代码即目标代码,目标代码基

Pytho核心编程笔记——第三章

第三章 Python基础 1.在Python中,赋值并不是直接将值赋给一个变量,对象是通过引用传递的,赋值时,是将该对象的引用(不是值)赋值给变量: i = 3,当值为3的对象创建后,会将该对象的引用赋值给变量 2.Python的赋值语句并不会返回值,所以a = (x = x +1)在Python中会报错 3.多元赋值时,等号两边的对象都是元组: a,b,c = 1,"str",23 4.Python 不支持重载 原文地址:https://www.cnblogs.com/hhj-stu