C# 异步编程之 Task 的使用
(说明:随笔内容为学习task的笔记,资料来源:https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task?redirectedfrom=MSDN&view=netframework-4.7.2,下面内容的图片大多来自msdn,不是的会说明)
一、什么是task?
Task 是一个独立的操作线程,通常是异步执行的。通过Task启动的异步操作线程是在线程池中执行的,也即Task使用的是线程池的线程。
测试一下Task使用线程池的证明:
代码如下:
public static void ThreadPoolTest()
{
Action action1 = () => { Console.WriteLine("I am Action, I don't need anything"); };
for (int i = ; i < ; i++)
{
new Task(action1).Start();
}
} public static void ThreadPoolTest2()
{
Action action1 = () => { Console.WriteLine("I am Action, I don't need anything"); };
for (int i = ; i < ; i++)
{
new Thread(new ThreadStart(Print)).Start();
}
} private static void Print()
{
Console.WriteLine("I am Action, I don't need anything");
}
运行结果:

这个是使用Windows Performence Monitor(性能监视器)监视的系统当前的线程数量情况,绿色的线代表的是当前应用程序托管的线程,包括正在运行的和已经停止的。图中绿色的线急剧上升的时候是我开始运行ThreadPoolTest2方法的时候(下降是我关闭程序的时候),而在后面当线程恢复平稳我运行ThreadPoolTest方法的时候线程的数量却没有什么变化。
二、Task的构造函数:
我们主要看以下几个:
1、Task(Action):
Action是没有返回值的委托。
简单来说,直接贴代码,这个是很简单的一个操作,也很常用:
public static void ActionParameter()
{
Action action1 = () => { Console.WriteLine("I am Action, I don't need anything"); };
Action<object> action2 = (o) => { Console.WriteLine("I am Action, My Name is:"+o); };
Task task1 = new Task(action1);
Task task2 = new Task(action2,"a");
Task task3 = new Task(action2, "b"); task1.Start();
task2.Start();
task3.Start();
}
2、Task(Action, CancellationToken)
先上例子:
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
var token = cancellationTokenSource.Token;
List<int> intList = new List<int>();
for (int i = ; i < ; i++)
{
intList.Add(i);
} Task t = Task.Run(() => { Parallel.ForEach(intList,
i => {
Console.WriteLine(i);
Interlocked.Increment(ref num);
Console.WriteLine("num is:" + num);
if (token.IsCancellationRequested)
token.ThrowIfCancellationRequested(); }
);
}, token); Thread.Sleep();
cancellationTokenSource.Cancel();
try
{
await t;
}
catch (AggregateException aggregateExceptions)
{
foreach (var ex in aggregateExceptions.InnerExceptions)
{
Console.WriteLine(ex.GetType().Name + "========================================");
}
}
finally
{
cancellationTokenSource.Dispose();
}
运行结果:
num is: num is:
num is: num is:
OperationCanceledException========================================
OperationCanceledException========================================
OperationCanceledException========================================
OperationCanceledException========================================
通过上面例子可以看到:
1、进行取消用的是 CancellationTokenSource (官方文档定义:向应该被取消的 System.Threading.CancellationToken 发送信号。)的属性Token(类型是CancellationToken);
2、我们在子线程中是用Parallel(用于并行编程,同时启用多个线程运行),在Parallel中当检查到当前线程已经取消都抛出了异常,但是我们try catch这些异常的地方是在await,这个是很重要的一点,而且,同时启动多个线程,异常是放在AggregateException 中;
3、我们有一行代码Thread.Sleep(5),让主线程睡眠了5毫秒,这个是为了让子线程能够获得时间片。如果不这么做很大的可能会使await等待的是一个已经取消的异步操作,会抛出TaskCanceledException异常,需要进行捕获。有兴趣可以尝试。
4、记得释放CancellationTokenSource
也可以在内部取消线程(仅展示修改的代码块):
Task t = Task.Run(() => {
Parallel.ForEach(intList,
i => {
Console.WriteLine(i);
Interlocked.Increment(ref num);
if (token.IsCancellationRequested)
token.ThrowIfCancellationRequested();
if (num > )
{
cancellationTokenSource.Cancel();
}
Console.WriteLine("num is:" + num);
}
);
}, token);
try
{
await t;
}
3、Task(Action, TaskCreationOptions)
Action我们已经了解了,主要看的是TaskCreationOptions,我们知道,这种命名的一般是枚举类型,看一下有什么枚举值,官网有解释:
3.1 AttachedToParent
看一下区别:

看示例代码:
public static async void CreateOptionTest()
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Task task = new Task(() =>
{ Task childTask = new Task(() =>
{
try
{
Thread.Sleep();
Console.WriteLine("child task is completed--------------------------");
throw new ChildIsCompletedException("just need a exception");
}
catch (ChildIsCompletedException ex)
{
throw ex;
}
}
//,TaskCreationOptions.AttachedToParent
);
childTask.Start(); Thread.Sleep();
Console.WriteLine("parent task is completed============================");
}, TaskCreationOptions.None); task.Start();
try
{
await task;
Console.WriteLine("parent task status:"+task.IsCompleted);
}catch(AggregateException aggreEx)
{
IReadOnlyCollection<Exception> exs = aggreEx.InnerExceptions;
foreach (var item in exs)
{
Console.WriteLine(item.GetType().Name);
}
}
}
有添加AttachedToParent的运行结果:
parent task is completed============================
child task is completed--------------------------
ChildIsCompletedException
没有添加的结果:
parent task is completed============================
parent task status:True
child task is completed--------------------------
没有添加到父任务的时候是没有抛出异常的,而且父任务完成了但是它还没有退出,需要等待子任务完成才算完成,然而子任务抛出了异常,所以它就挂了,抛出了子任务的异常,而不附加到父任务的时候,就没有异常抛出,父任务正常完成了。
3.2 DenyChildAttach 使父任务拒绝任何尝试的子任务附加;
在3.1的例子中,我们父任务的TaskCreationOptions的值是None,改成DenyChildAttach,即使子任务使用了AttachedToParent,输出结果也会是像没有添加一样。
4、 属性:
4.1 AsyncState:
AsyncState为传入线程的参数,类型是Object,以委托Action创建线程为例,委托Action可以传入一个参数,AsyncState就是这个参数,请见:
public static void GetAsyncStateTest()
{
Func<int> func = () => *;
Task task = new Task((x) => { Console.WriteLine("I am Action"); }, "I am AsyncState");
task.Start();
Console.WriteLine(task.AsyncState);
}
运行结果:
I am AsyncState
I am Action
4.2 CompletedTask (与FromResult<T>(T object)相比)
CompletedTask和FromResult都返回一个状态为RanToCompletion的Task,区别是一个有返回值一个没有。当我们允许一个线程需要返回一个task的时候,如果在早期就已经知道了结果线程不需要继续往下运行可以根据需不需要返回值使用这两个中的一个。
public static void GetCompletedTask()
{
Func<Task<string>> funcTask = () =>
{
for (int i = ; i < ; i++)
{
if (i > )
{
return Task.FromResult<string>("已完成");
}
} return new Task<string>((x) => { return (string)x; }, "全部完成");
}; Func<Task> funcTaskNotResult = () =>
{
for (int i = ; i < ; i++)
{
if (i > )
{
return Task.CompletedTask;
}
} return new Task<string>((x) => { return (string)x; }, "全部完成");
}; Task<string> task=Task.Run<string>(funcTask);
Task taskNotResult = Task.Run(funcTaskNotResult);
Thread.Sleep();
Console.WriteLine("task result:"); Console.WriteLine("status:"+task.Status);
Console.WriteLine("is completed:"+task.IsCompleted);
Console.WriteLine("result"+task.Result);
Console.WriteLine("taskNotResult result:");
Console.WriteLine("status:" + taskNotResult.Status);
Console.WriteLine(taskNotResult.IsCompleted);
}
返回结果:
task result:
status:RanToCompletion
is completed:True
result已完成
taskNotResult result:
status:RanToCompletion
True
持续更新中 ing
C# 异步编程之 Task 的使用的更多相关文章
- net异步编程之await
net异步编程之await 初探asp.net异步编程之await 终于毕业了,也顺利进入一家期望的旅游互联网公司.27号入职.放肆了一个多月没写代码,好方啊. 另外一下观点均主要针对于await ...
- python异步编程之asyncio
python异步编程之asyncio 前言:python由于GIL(全局锁)的存在,不能发挥多核的优势,其性能一直饱受诟病.然而在IO密集型的网络编程里,异步处理比同步处理能提升成百上千倍的效率, ...
- 异步编程之Generator(1)——领略魅力
异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...
- 异步编程之Promise(3):拓展进阶
异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...
- 异步编程之Promise(2):探究原理
异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...
- (翻译)异步编程之Promise(1):初见魅力
原文:https://www.promisejs.org/ by Forbes Lindesay 异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2) ...
- Javascript异步编程之setTimeout与setInterval详解分析(一)
Javascript异步编程之setTimeout与setInterval 在谈到异步编程时,本人最主要会从以下三个方面来总结异步编程(注意:特别解释:是总结,本人也是菜鸟,所以总结不好的,请各位大牛 ...
- 异步编程之co——源码分析
异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...
- 异步编程之Generator(2)——剖析特性
异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...
随机推荐
- Ubuntu下 MySql忘记密码解决方案
1.在终端输入 sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf 2.在文件内搜索skip-external-locking,在下面添加一行: skip-gran ...
- 20165221 《网络对抗技术》EXP1 PC平台逆向破解
20165221 <网络对抗技术>EXP1 PC平台逆向破解 一.实验内容 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函 ...
- 第一章 初识Mysql
Mysql是一个开放源代码的数据库管理系统(DBMS),它是由MySQL AB 公司开发.发布并支持的. 登录 -- mysql #本地登录,默认用户root,空密码,用户为root@127.0.0. ...
- Day 18: 记filebeat内存泄漏问题分析及调优
ELK 从发布5.0之后加入了beats套件之后,就改名叫做elastic stack了.beats是一组轻量级的软件,给我们提供了简便,快捷的方式来实时收集.丰富更多的数据用以支撑我们的分析.但由于 ...
- pwnable.tw calc
题目代码量比较大(对于菜鸡我来说orz),找了很久才发现一个能利用的漏洞 运行之发现是一个计算器的程序,简单测试下发现当输入的操作数超过10位时会有一个整型溢出 这里调试了一下发现是printf(&q ...
- 【算法】CRF(条件随机场)
CRF(条件随机场) 基本概念 场是什么 场就是一个联合概率分布.比如有3个变量,y1,y2,y3, 取值范围是{0,1}.联合概率分布就是{P(y2=0|y1=0,y3=0), P(y3=0|y1= ...
- 《剑指offer》二叉树的深度
本题来自<剑指offer> 反转链表 题目: 思路: C++ Code: Python Code: 总结:
- 通过GIT_COMMIT进行代码回滚
首先需要安装插件:conditional-buildstep A buildstep wrapping any number of other buildsteps, controlling thei ...
- C# 操作docx文档
一.需要引用DocX类库文件,可以直接在NuGet中找到. 二.创建文件,并添加一张表格 public static string fileName = AppDomain.CurrentDomain ...
- Canvas中如何画一条清晰的线宽为奇数(如1px逻辑像素)的线?
我在开发中使用canvas的机会不是很多,但是第一次实际使用中就遇到了问题,"很久很久以前,我自己画了一个雷达图,线宽都是1像素,但是显示效果不如期望,这才发现canvas中的画线还是有坑的 ...