zoukankan      html  css  js  c++  java
  • 并发系列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;
    }
    

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

  • 相关阅读:
    JDK1.8HashMap底层实现原理
    关于map转json,空key丢失的问题
    spring一些注解的使用及相关注解差异
    搭建基础项目遇到的一些小坑
    解析ftp上word文档的文字并输入
    R语言中回归模型预测的不同类型置信区间应用比较分析
    R语言中的广义线性模型(GLM)和广义相加模型(GAM):多元(平滑)回归分析保险资金投资组合信用风险敞口
    R语言对巨灾风险下的再保险合同定价研究案例:广义线性模型和帕累托分布Pareto distributions分析
    R语言中GLM(广义线性模型),非线性和异方差可视化分析
    如何用R语言绘制生成正态分布图表
  • 原文地址:https://www.cnblogs.com/mengcheng9300/p/12661742.html
Copyright © 2011-2022 走看看