(说明:随笔内容为学习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 的使用的更多相关文章

  1. net异步编程之await

    net异步编程之await 初探asp.net异步编程之await   终于毕业了,也顺利进入一家期望的旅游互联网公司.27号入职.放肆了一个多月没写代码,好方啊. 另外一下观点均主要针对于await ...

  2. python异步编程之asyncio

    python异步编程之asyncio   前言:python由于GIL(全局锁)的存在,不能发挥多核的优势,其性能一直饱受诟病.然而在IO密集型的网络编程里,异步处理比同步处理能提升成百上千倍的效率, ...

  3. 异步编程之Generator(1)——领略魅力

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  4. 异步编程之Promise(3):拓展进阶

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  5. 异步编程之Promise(2):探究原理

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  6. (翻译)异步编程之Promise(1):初见魅力

    原文:https://www.promisejs.org/ by Forbes Lindesay 异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2) ...

  7. Javascript异步编程之setTimeout与setInterval详解分析(一)

    Javascript异步编程之setTimeout与setInterval 在谈到异步编程时,本人最主要会从以下三个方面来总结异步编程(注意:特别解释:是总结,本人也是菜鸟,所以总结不好的,请各位大牛 ...

  8. 异步编程之co——源码分析

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  9. 异步编程之Generator(2)——剖析特性

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

随机推荐

  1. 开源litemall学习

    1参数拼装 https://blog.yeskery.com/articles/345298282 WxWebMvcConfiguration HandlerMethodArgumentResolve ...

  2. JAVA实例

     JAVA实例1  1 package Demo3; import java.io.File; import java.io.FileReader; import java.io.IOExceptio ...

  3. Python 并发编程

    进程 开启进程 from multiprocessing import Process import time def task(name): print('%s is running' %name) ...

  4. debug 2

    Red Hat Developer Toolsetdelivers the latest stable versions of essential GCC C, C++, Fortran, and s ...

  5. 关于 X509Certificate2 程序发布IIS后找不到文件路径的问题

    有很多支付类.物联网等平台调用接口时需要用到证书: 通过X509Certificate2 类加载证书在程序发布之后发现无法找到证书路径,但是通过文件查找方法又可以检测到该文件. X509Certifi ...

  6. 从头开始学Maven【依赖范围】

    例如 <dependencies> <dependency> <groupId></groupId> <artifactId></ar ...

  7. Springboot2新特性概述

    官方说明: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Release-Notes 起码 JDK 8 和支持 ...

  8. python正则表达式--split、sub、escape方法

    1.re.split 语法: re.split(pattern, string[, maxsplit=0, flags=0]) 参数: pattern    匹配的正则表达式 string      ...

  9. Jmeter JDBC Connection Configuration 链接失败,提示Error preloading the connection pool

    修改数据配置的连接数即可:修改为小一点 下面是oracle 配置连接的方式

  10. Java 批量修改文件夹里面的文件的名字

    背景:公司要求使用PADS完成原理图设计.PCB Layout.而他硬件工程师要求我在将PADS的库文件发送给他们之前,必须在每一个库文件的后面追加今天的日期,再发送给他们. 问题来了,如果一次需要发 ...