多线程三:Task
Task是.NET 3.0中推出的,是基于ThreadPool封装的,里面的线程都是来自于ThreadPool。
1、使用Run()方法启动线程
F12查看Run()方法的定义:
发现Run()方法的参数是一个Action类型的委托,那么可以使用下面的方式启动多线程:
// 使用Run()方法启动线程 Task.Run(() => this.DoSomethingLong("btnTask_Click1")); Task.Run(() => this.DoSomethingLong("btnTask_Click2"));
2、使用TaskFactory的StartNew()方法
// 使用TaskFactory启动 TaskFactory taskFactory = Task.Factory; taskFactory.StartNew(() => this.DoSomethingLong("btnTask_Click3"));
3、使用Task的构造函数启动
// 使用构造函数启动 Task task= new Task(() => this.DoSomethingLong("btnTask_Click4")); task.Start();
效果:
下面来看看一个案例:
拿编写程序为例来说明:在一个项目中,项目经理负责前期的一些准备工作,相当于是主线程,其他开发人员负责具体的编码工作,相当于子线程,那么可以使用这个例子来模仿多线程。
1、先编写一个编码的方法:
/// <summary> /// 编码的方法 /// </summary> /// <param name="name">开发人员Name</param> /// <param name="project">负责的模块</param> private void Coding(string name, string project) { Console.WriteLine($")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); ; ; i < ; i++) { lResult += i; } //Thread.Sleep(2000); Console.WriteLine($")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************"); }
2、启动线程
Console.WriteLine($")}】"); Console.WriteLine($")}】"); Console.WriteLine($")}】"); Task.Run(() => this.Coding("Tom", "Client")); Task.Run(() => this.Coding("Jack", "Service"));
结果:
这时又提出了新的需求:必须所有编码工作都完成以后才能上线使用,将代码修改如下:
Console.WriteLine($")}】"); Console.WriteLine($")}】"); Console.WriteLine($")}】"); Task.Run(() => this.Coding("Tom", "Client")); Task.Run(() => this.Coding("Jack", "Service")); Console.WriteLine($")}】");
再次运行程序,效果如下:
从上面的截图中看出:这不是我们想要的效果,编码工作还没有结束就可以上线使用了,即子线程还没有结束,主线程就已经结束了。要想实现我们想要的效果,那么必须使主线程等待子线程都结束以后,主线程才能结束。这时可以使用Task提供的WaitAll()方法实现,F12查询WaitAll()方法的定义:
WaitAll()方法有很多重载,我们在这里使用第一个重载方法,即参数是Task[]数组。查看Run()方法的定义时,我们会发现Run()方法的返回值就是Task类型,那么我们可以将代码进行如下的修改:
List<Task> taskList = new List<Task>(); Console.WriteLine($")}】"); Console.WriteLine($")}】"); Console.WriteLine($")}】"); taskList.Add( Task.Run(() => this.Coding("Tom", "Client"))); taskList.Add( Task.Run(() => this.Coding("Jack", "Service"))); // 等待集合中的所有线程都执行完 Task.WaitAll(taskList.ToArray()); Console.WriteLine($")}】");
然后运行程序,查看效果:
可以看出:这次就是我们想要的效果。但是在运行程序的时候会发现,使用了WaitAll()方法以后,界面会卡住,也就是说WaitAll()方法会阻塞当前线程,等着全部任务都执行完以后,才会进入下一行。
注意:WaitAll()除了上面使用的方法以外,还有带时间参数的重载方法,表示会等待多长时间,无论所有任务是否都完成。例如:
List<Task> taskList = new List<Task>(); Console.WriteLine($")}】"); Console.WriteLine($")}】"); Console.WriteLine($")}】"); taskList.Add( Task.Run(() => this.Coding("Tom", "Client"))); taskList.Add( Task.Run(() => this.Coding("Jack", "Service"))); //限时等待,最多等待1秒 Task.WaitAll(taskList.ToArray(), ); Console.WriteLine("等待1s之后,执行的动作"); // 等待集合中的所有线程都执行完 Task.WaitAll(taskList.ToArray()); Console.WriteLine($")}】");
效果:
这时需求又有了变化:只要其中一个模块完成,就相当于完成了里程碑的工作,这时可以用Task提供的WaitAny()方法实现。F12查询WaitAny()的定义:
WaitAny()表示等待其中任何一个任务完成就会进入下一行,代码修改如下:
List<Task> taskList = new List<Task>(); Console.WriteLine($")}】"); Console.WriteLine($")}】"); Console.WriteLine($")}】"); taskList.Add( Task.Run(() => this.Coding("Tom", "Client"))); taskList.Add( Task.Run(() => this.Coding("Jack", "Service"))); Task.WaitAny(taskList.ToArray()); Console.WriteLine($")}】"); ////限时等待,最多等待1秒 //Task.WaitAll(taskList.ToArray(), 1000); //Console.WriteLine("等待1s之后,执行的动作"); //// 等待集合中的所有线程都执行完 Task.WaitAll(taskList.ToArray()); Console.WriteLine($")}】");
效果:
注意:WaitAny()同样也会阻塞当前线程,卡住界面。和WaitAll()一样,WaitAny()也有带时间参数的重载方法,表示等待多长时间。
应用场景:
1、WaitAll():假如一个界面需要的数据,来自不同的数据源,那么这时可以使用WaitAll()等待所有的数据都查询完成以后才显示界面。
2、WaitAny():商品查询,只要查询出某一个符合条件的即可。
上面讲到的WaitAll()和WaitAny()都会卡住界面,那么有没有不卡界面的方法呢?答案是肯定的:那就是WhenAll()和WhenAny().。
从上面的截图中可以看出,WhenAll()的参数还是一个Task[]类型的数组,返回值是Task类型,表示Task[]数组里面的所有任务都完成以后,创建一个新的Task。这时可以继续调用Task类提供的ContinueWith()方法。ContinueWith()方法表示Task任务完成时异步执行的延续任务。
List<Task> taskList = new List<Task>(); Console.WriteLine($")}】"); Console.WriteLine($")}】"); Console.WriteLine($")}】"); taskList.Add(Task.Run(() => this.Coding("Tom", "Client"))); taskList.Add(Task.Run(() => this.Coding("Jack", "Service"))); Task.WhenAny(taskList.ToArray()).ContinueWith(t => { Console.WriteLine($")}】"); }); Task.WhenAll(taskList.ToArray()).ContinueWith(t => { Console.WriteLine($")}】"); });
效果:
注意:
除了Task可以实现这种效果以为,TaskFactory也可以实现,例如:
TaskFactory taskFactory = new TaskFactory(); taskFactory.ContinueWhenAll(taskList.ToArray(), tList => { Console.WriteLine($")}】"); }); taskFactory.ContinueWhenAny(taskList.ToArray(), t => { Console.WriteLine($")}】"); });
多线程三:Task的更多相关文章
- 【多线程】 Task
[多线程] Task 一. 常用方法: 1. ContinueWith : 当前 Task 完成后, 执行传入的 Task 2. Delay : 创建一个等待的 Task,只有在调用 Wait 方法时 ...
- 多线程(三) java中线程的简单使用
java中,启动线程通常是通过Thread或其子类通过调用start()方法启动. 常见使用线程有两种:实现Runnable接口和继承Thread.而继承Thread亦或使用TimerTask其底层依 ...
- java 多线程三
java 多线程一 java 多线程二 java 多线程三 java 多线程四 注意到 java 多线程一 中 MyThread2 运行结果出现0.-1,那是因为在操作共享数据时没有加锁导致. 加锁的 ...
- 【多线程】 Task ,async ,await
[多线程]Task ,async ,await 一. WinForm 里经常会用到多线程, 多线程的好出就不多说了,来说说多线程比较麻烦的地方 1. UI 线程与其他线程的同步,主要是 Form 和 ...
- 细说.NET中的多线程 (三 使用Task)
上一节我们介绍了线程池相关的概念以及用法.我们可以发现ThreadPool. QueueUserWorkItem是一种起了线程之后就不管了的做法.但是实际应用过程,我们往往会有更多的需求,比如如果更简 ...
- JAVA基础知识之多线程——三种实现多线程的方法及区别
所有JAVA线程都必须是Thread或其子类的实例. 继承Thread类创建线程 步骤如下, 定义Thead子类并实现run()方法,run()是线程执行体 创建此子类实例对象,即创建了线程对象 调用 ...
- Java多线程——<三>简单的线程执行:Executor
一.概述 按照<Java多线程——<一><二>>中所讲,我们要使用线程,目前都是显示的声明Thread,并调用其start()方法.多线程并行,明显我们需要声明多个 ...
- 【多线程】Task
介绍 Task是.NET推出数据任务处理的工作类.位于System.Threading.Tasks命名空间下,通过命名空间也可以看出是个多线程类. 创建Task: Task有很多构造函数,无参有参都有 ...
- java多线程(三)——锁机制synchronized(同步语句块)
用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法之行一个长时间的任务,那么B线程必须等待比较长的时间,在这样的情况下可以使用synchronized同步语句快来解 ...
随机推荐
- js判断客户端是否是IOS系统
在手机端应用的开发中,经常会碰到IOS系统跟Android系统去访问同一个内容时的展示效果不同,这时候我们需要区别对待,下面代码就是用js判断手机终端是否IOS系统: //判断是否为ios系统:是IO ...
- 华中科技大学 ubuntu14.04源
deb http://mirrors.hust.edu.cn/ubuntu/ trusty main restricteddeb-src http://mirrors.hust.edu.cn/ubun ...
- unity, Collider2D.attachedRigidbody
boss根节点上挂RigidBody2D(且boss根节点以下任何子节点均不挂RigidBody2D),boss腿部骨骼节点挂collider2D,标签为"bossLeg",bos ...
- C# Split() 去除 \r\n 分组
str为读入的文本string[] ReadText = str.Replace("\r\n", "@").Split('@'); 转自 http://zhid ...
- Tcp超时修改
Linux 建立 TCP 连接的超时时间分析 tags: linux | network Linux 系统默认的建立 TCP 连接的超时时间为 127 秒,对于许多客户端来说,这个时间都太长了, 特别 ...
- 本地搭建 Gradle 服务器,提高 Android Studio Gradle 下载速度
AndroidStudio 更新以后,在公司网会卡在下载 Gradle 的地方,下载 Gradle 速度很慢. 看到别人的博客提供的解决办法本地搭建一个 Gradle 的服务器,然后把 Android ...
- Android xUtils3源代码解析之网络模块
本文已授权微信公众号<非著名程序猿>原创首发,转载请务必注明出处. xUtils3源代码解析系列 一. Android xUtils3源代码解析之网络模块 二. Android xUtil ...
- 【小白的CFD之旅】21 网格划分软件的选择
但是怎样才能获得流体计算网格呢?“工欲善其事必先利其器”,画网格该用什么器呢?小白决定找黄师姐请教一番. 小白找到黄师姐的时候,黄师姐正在电脑上忙着. “黄师姐,我发现网格划分软件有好多种,究竟哪种才 ...
- [PY3]——环境配置(1)——pyenv | pip | ipython | jupyter(含安装pyenv环境shell脚本)
1.关于pyenv (1)pyenv是一个开源的.shell脚本编写的工具:Simple Python version management (2)为什么使用pyenv:当多个项目同时在开发与维护时, ...
- 沐雪多用户微信公众平台开发源码,商城小程序源码(2018年最新的asp.net C# 微信源码,小程序源码)
现售价5400元,就可以搭建自己的微信平台啦 购买地址:https://item.taobao.com/item.htm?id=539102325336 该系统是由[上海沐雪网络]独家授权销售,其他地 ...