20181105_线程之Task
Task是基于.net Framework3.0框架, Task使用的线程也是来自于ThreadPool
多线程的两个意义: 优化体验(常见于不卡界面), 提升运行速度(不同线程可以分担运算任务)
总结:
//Task6个方法:
WaitAll Task.WaitAny(taskList.ToArray());//会阻塞当前线程,等着某个任务完成后,才进入下一行 卡界面; 有好几个重载, 超时. . .
WaitAny //Task.WaitAny(taskList.ToArray());//会阻塞当前线程,等着[某个任务]完成后(只要有一个完成, 就会进入下一行代码),才进入下一行 卡界面 应用场景
//一个业务查询操作有多个数据源 首页--多线程并发--拿到全部数据后才能返回 WaitAll
//一个商品搜素操作有多个数据源,商品搜索--多个数据源--多线程并发--只需要一个结果即可-- WhenAll 这个WhenAll啥也没有做, 就是表示当所有线程都把事情做完之后,然后再去做什么; 他必须要和ContinuWith一起使用, 否则便失去意义; Task.WhenAll(taskList).ContinueWith(()={"一起去吃饭"});翻译一下就是, 当tasklist中所有线程都完成工作了, 那么继续执行 一起去吃饭
WhenAny 这个和WhenAll一样. 但是指的是任意一个线程完成 ContinueWith ContinueWhenAll taskFactory.ContinueWhenAll 在taskFactory中也有类似的WhenAll 和 WhenAny //Task.Delay(1000);//延迟 不会卡
//Thread.Sleep(1000);//等待 卡
一. Task.Run→线程的启动是基于异步形式, 下面代码演示使用Task/new Task() / TaskFactory方式来启动线程:
Task.Run(() => this.DoSomethingLong("btnTask_Click1"));//Task的Run在.net 4.5 的时候才有
TaskFactory taskFactory = Task.Factory;//从.net 4.0开始才有
taskFactory.StartNew(() => this.DoSomethingLong("btnTask_Click3")); //利用TaskFactroy来启动一个新的线程 Task t = new Task(() => { Console.WriteLine("opasdfawerfwe"); }); t.Start();
二. 使用task实现等待当前线程完成, WaitAll和WaitAny, 然后继续后面的任务(卡界面):
////什么时候用多线程? 任务能并发运行;提升速度;优化体验
List<Task> taskList = new List<Task>();
Console.WriteLine($"项目经理启动一个项目。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
taskList.Add(Task.Run(() => this.Coding("悟空", "Client")));//做客户端
taskList.Add(Task.Run(() => this.Coding("八戒", "Portal")));//做门户(后台)
taskList.Add(Task.Run(() => this.Coding("唐僧", "Service")));//做服务
taskList.Add(Task.Run(() => this.Coding("如来", "Jump"))); //做项目跳转
taskList.Add(Task.Run(() => this.Coding("沙僧", "Monitor")));//做监控系统
////阻塞:需要完成后再继续, 谁执行下面的Task, 就会阻塞谁
Task.WaitAll(taskList.ToArray());//会阻塞当前线程,等着 [全部任务] 完成后,才进入下一行 卡界面 Task.WaitAny(taskList.ToArray());//会阻塞当前线程,等着 [某个任务] 完成后(只要有一个完成, 就会进入下一行代码),才进入下一行 卡界面,多线程加快速度,但是全部任务完成后,才能执行的操作
Task.WaitAny(taskList.ToArray(), 1000); //限时等待 Console.WriteLine($"告诉甲方验收,上线使用【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
小结:
waitAll→一个业务查询操作有多个数据源 首页--多线程并发--拿到全部数据后才能返回 WaitAll
WaitAny→一个商品搜素操作有多个数据源,商品搜索--多个数据源--多线程并发--只需要一个结果即可--WaitAny
三. 使用WaitAll或WaitAny即等待任务完成, 又不卡UI的方法, 包一层
Task.Run( //再包一层Task, 就是避开当前的UI线程来执行运算方法
() =>
{
//多线程加快速度,但是全部任务完成后,才能执行的操作
Task.WaitAll(taskList.ToArray());//会阻塞当前线程,等着全部任务完成后,才进入下一行 卡界面
Console.WriteLine($"告诉甲方验收,上线使用【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
四. 使用WhenAll 和 WhenAny, 来实现即不卡界面, 又可以控制执行顺序(等待所有任务完成, 才执行后续任务)
//当任何一个(WhenAny)线程完成任务, 就继续执行(ContinueWith)后面的动作
Task.WhenAny(taskList.ToArray()).ContinueWith(t =>
{
Console.WriteLine(taskList.ToArray().FirstOrDefault(s => s.Status == TaskStatus.RanToCompletion));
Console.WriteLine($"风骚的笑. . .【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
}) ;
//当所有(WhenAll)线程完成任务, 就继续执行(ContinueWith)后面的动作
Task.WhenAll(taskList.ToArray()).ContinueWith(t =>
{
Console.WriteLine($"部署环境,联调测试。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
}) ;
五. 实战:
a) Task控制线程数量控制, 完成1000个任务, 但是最多只能启动11个线程, 代码如下:
//Task控制线程数量
List<int> list = new List<int>();
for (int i = 0; i < 10000; i++)
{
list.Add(i);
}
//项目规定完成10000个任务 但是最多只能有11个线程
Action<int> action = i =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString("00"));
Console.WriteLine($"当前i的值是→{ i.ToString("00")}");
Thread.Sleep(new Random(i).Next(100, 300));
};
List<Task> taskList = new List<Task>(); //将任务从list中取出来
foreach (var i in list)
{
int k = i;
taskList.Add(Task.Run(() => action.Invoke(k))); //每创建一个任务, 就将任务添加到itasklist中; 这里是异步执行的
if (taskList.Count > 10)//检查是否大于10, 就开始等待; 注意如果这样判断的话, 其实当前用了11个线程
{
//WaitAny 也是卡界面
Task.WaitAny(taskList.ToArray());//最起码要完成一个
//这一步检查线程的状态, 如果线程的状态不等于 已完成 的, 则继续保留在taskList中
taskList = taskList.Where(t => t.Status != TaskStatus.RanToCompletion).ToList();
//var v = taskList.Max(m => m.Id);
//Console.Write(v + "....................
.................");
}
}
//等待所有线程完成后, 开始后续的任务
Task.WhenAll(taskList.ToArray());
b) 使用TaskFactory的AsyncState来明确哪一个线程最先完成任务
//不能使用Task启动,使用TaskFactory是可以的, 可以使用t.AsyncState状态来标识
TaskFactory taskFactory1 = new TaskFactory();
List<Task> taskList = new List<Task>();
taskList.Add(taskFactory1.StartNew(o => this.Coding("悟空", "Client"), "悟空"));
taskList.Add(taskFactory1.StartNew(o => this.Coding("八戒", "Portal"), "八戒"));
taskList.Add(taskFactory1.StartNew(o => this.Coding("沙僧", "Service"), "沙僧"));
//只要有任何一个人完成任务之后, 就获取整个人的编号
taskFactory1.ContinueWhenAny(taskList.ToArray(), t =>
{
Console.WriteLine(t.AsyncState);
Console.WriteLine($"部署环境,联调测试。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
});
//当所有的人都完成任务之后, 获取第一个完成任务的人
taskFactory1.ContinueWhenAll(taskList.ToArray(), tList =>
{
Console.WriteLine(tList[0].AsyncState);
Console.WriteLine($"部署环境,联调测试。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
});
c) Delay和Sleep
{
//Task.Delay(1000);//延迟 不会卡 ; 延迟1秒钟后, 执行后续动作
//Thread.Sleep(1000);//等待 卡 Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Thread.Sleep(2000);
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
} {
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
//不卡界面; 然后会等待2000毫秒后去执行continueWith中的函数;
Task.Delay(2000).ContinueWith(t =>
{
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
});
} {
//使用Task.Run将Thread.Sleep包一层 同样可以实现不卡界面, 延迟执行
//Stopwatch stopwatch = new Stopwatch();
//stopwatch.Start();
//Task.Run(() =>
//{
// Thread.Sleep(2000);
// stopwatch.Stop();
// Console.WriteLine(stopwatch.ElapsedMilliseconds);
//});
}
d) Task指定回调 ; ContinueWith
Task.Run(() => this.Coding("悟空", "Client")).ContinueWith(t => { });
六. 使用Parallel并行编程, 在Task的基础上做了封装, 从.net Framework4.0开始
a) 使用Parallel并行编程完成一个多线程启动; 注意这个会卡界面; 因为主线程参与了计算
//当然这个也可以使用Task来完成
Parallel.Invoke(() => this.Coding("悟空", "Client")
, () => this.Coding("八戒", "Portal")
, () => this.Coding("沙僧", "Service"));
b) 一些简单API; 使用for和foreach
//for循环的操作; 启动5个线程; 0表示for的开始, 5表示结束; 简化的for
Parallel.For(0, 5, i => this.Coding("悟空", "Client" + i));
//使用foreach; 对集合中的每一个元素都执行后面的Action
Parallel.ForEach(new string[] { "0", "1", "2", "3", "4" }, i => this.Coding("悟空", "Client" + i));
c) 使用 parallel来控制当前最大的线程数量; 卡界面
//parallelOptions 可以控制并发数量;控制线程数量;
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = 3; //任意时刻只有三个线程在执行
Parallel.For(0, 10, parallelOptions, i => this.Coding("悟空", "Client" + i));
d) 使用 parallel来控制当前最大的线程数量; 不卡界面
Task.Run(() =>
{
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = 3;
Parallel.For(0, 10, parallelOptions, i => this.Coding("悟空", "Client" + i));
});
e) Parallel的break和stop, 不推荐使用
//Break Stop 都不推荐用
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = 3;
Parallel.For(0, 40, parallelOptions, (i, state) =>
{
if (i == 2)
{
Console.WriteLine($"线程Break,当前任务结束 i={i} {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
state.Break();//结束Parallel当次的这一次操作 结束了当前的线程的操作, 如果当前线程操作了很多i , 那么这个线程所操作的i就不会输出了; 但是如果当前线程如果是主线程的话, 那么它会直接结束Parallel的, 这要看运气了. . .
return;//必须带上
}
//if (i == 20)
//{
// Console.WriteLine($"线程Stop,Parallel结束 i={i} {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
// state.Stop();//结束Parallel全部操作 等于break
// return;//必须带上
//}
this.Coding("悟空", "Client" + i);
});
//Break 实际上结束了当前这个线程;如果是主线程,等于Parallel都结束了
//多线程的终止本身就不靠谱
20181105_线程之Task的更多相关文章
- Asp.Net Core 轻松学-多线程之Task(补充)
前言 在上一章 Asp.Net Core 轻松学-多线程之Task快速上手 文章中,介绍了使用Task的各种常用场景,但是感觉有部分内容还没有完善,在这里补充一下. 1. 任务的等待 在使用 ...
- WebAPI调用笔记 ASP.NET CORE 学习之自定义异常处理 MySQL数据库查询优化建议 .NET操作XML文件之泛型集合的序列化与反序列化 Asp.Net Core 轻松学-多线程之Task快速上手 Asp.Net Core 轻松学-多线程之Task(补充)
WebAPI调用笔记 前言 即时通信项目中初次调用OA接口遇到了一些问题,因为本人从业后几乎一直做CS端项目,一个简单的WebAPI调用居然浪费了不少时间,特此记录. 接口描述 首先说明一下,基于 ...
- C# 多线程之Task资料
博客 Stephen Toub From MicroSoft Crop. Stephen Cleary Parallelism in .NET 文章 It's All About the Sync ...
- 【C#】线程之Task
Task开启线程 有两种启动方式: 1.构造创建线程,然后启动 var taskForAction = new Task(() => { //do something }); taskForAc ...
- Asp.Net Core 轻松学-多线程之Task快速上手
前言 Task是从 .NET Framework 4 开始引入的一项基于队列的异步任务(TAP)模式,从 .NET Framework 4.5 开始,任何使用 async/await 进行修饰 ...
- C# 多线程之Task(任务
1.简介 为什么MS要推出Task,而不推Thread和ThreadPool,以下是我的见解: (1).Thread的Api并不靠谱,甚至MS自己都不推荐,原因,它将整个Thread类都不开放给W ...
- 【C#】线程之Parallel
在一些常见的编程情形中,使用任务也许能提升性能.为了简化变成,静态类System.Threading.Tasks.Parallel封装了这些常见的情形,它内部使用Task对象. Parallel.Fo ...
- Java多线程之Runnable与Thread
Java多线程之Thread与Runnable 一.Thread VS Runnable 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类和 ...
- JAVA多线程之UncaughtExceptionHandler——处理非正常的线程中止
JAVA多线程之UncaughtExceptionHandler——处理非正常的线程中止 背景 当单线程的程序发生一个未捕获的异常时我们可以采用try....catch进行异常的捕获,但是在多线程环境 ...
随机推荐
- 剑指offer--43.连续子数组的最大和
最大子段和,最大能取所有 ---------------------------------------------------------------- 时间限制:1秒 空间限制:32768K 热度 ...
- C#设置System.Net.ServicePointManager.DefaultConnectionLimit,突破Http协议的并发连接数限制
在Http协议中,规定了同个Http请求的并发连接数最大为2. 这个数值,可谓是太小了. 而目前的浏览器,已基本不再遵循这个限制,但是Dot Net平台上的 System.Net 还是默认遵循了这个标 ...
- UART介绍
https://baike.baidu.com/item/UART/4429746?fr=aladdin
- 国内知名的自然语言处理(NLP)团队
工业界 腾讯人工智能实验室(Tencent AI Lab) 百度自然语言处理(Baidu NLP):对外提供了百度AI开放平台,王海峰(现任百度副总裁,AI技术平台体系AIG总负责人) 微软亚洲研究院 ...
- IOS开发 Application Kit框架的线程安全
以下部分介绍了Application Kit框架的线程安全. 非线程安全类 以下这些类和函数通常是非线程安全的.大部分情况下,你可以在任何线程使用这些类,只要你在同一时间只有一个线程使用它们.查看这些 ...
- C#将html代码转换成文本代码
/// <summary> /// 去除HTML标记 /// </summary> /// <param name="strHtml">包括HT ...
- #Eclipse web工程 部署 三种方式 3
Eclipse web工程 部署 三种方式 3.热部署 在Eclipse中,实现 修改一个.java文件或者.jsp文件甚至是配置文件,不需要重启WEB服务器的前提下让修改生效,实现tomcat自动加 ...
- Eclipse web工程 部署 三种方式 1
Eclipse web工程 部署 三种方式 1.run on 前提: 安装 好 eclipse.jdk.tomcat 然后 新建一个 web工程 注意此处Default output folder 最 ...
- 跳转后全屏,兼容大部分浏览器JavaScript
<!DOCTYPE html> <html> <head> <title>测试</title> </head> <body ...
- save the transient instance before flushing错误解决办法 【待完善】
近日在项目中遇到以下错误,着实郁闷了一把: org.hibernate.TransientObjectException: object references an unsaved transient ...