(说明:随笔内容为学习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. vue路由--网站导航功能

    1.首先需要按照Vue router支持 npm install vue-router然后需要在项目中引入: import Vue from 'vue' import VueRouter from ' ...

  2. python epoll方式tcp连接回发消息

    # -*- coding:utf-8 -*- import socket import select class testserver(): def __init__(self): self.serv ...

  3. 阿里云服务器+ftp文件操作+基于Centos7的vsftpd配置

    路径问题:一定要注意此位置是否需要加入"/" 文件上传方式:被动模式 vsftp完整配置: # # The default compiled in settings are fai ...

  4. Python3的保留字

    Python3的保留字 false none true and 表示条件的并列,并且条件全部成立 as assert break class continue def del elif else ex ...

  5. 多个python版本共存

    windows下多个python版本共存 了解python的人都知道python有2.x版本和3.x版本,而python3.x版本不向下兼容,但是根据具体的需要,有时候要2.x和3.x共存,pytho ...

  6. Lua教程

    Lua中的类型与值 Lua中的表达式 Lua中的语句 Lua中的函数 Lua中的闭包 Lua 中 pairs 和 ipairs 的区别 Lua中的迭代器与泛型for Lua中的协同程序 Lua中__i ...

  7. Nodejs安装(npm、cnpm、webpack)

    1.nodejs官网对应下载(我的电脑对应的是64位的).https://nodejs.org/en/download/ 2.下载之后开始安装: 点击next按钮 点击next 点击next,进入下边 ...

  8. 【DOS】Win7系统文件夹名太长无法删除问题的解决

    一个测试工具产生了几个坑爹文件夹名为n个“x” ,系统提示删除不掉. 网上百度,说什么压缩.写bat文件...统统没用. 猛地看到右击菜单中安装了git客户端工具,想试试看.在该文件夹目录下Git B ...

  9. vscode中vue代码颜色插件

    vue提示插件[Vscode]       编者寄语:vscode的确是前端开发中很好的工具,安装颜色插件,从视觉上是美的享受.曾经的我遇到了vscode代码全是灰色,黑色的困惑,后来整理找到方法,整 ...

  10. docker启动,重启,停止容器

    docker 启动已经停止的容器 docker start 容器ID或容器名 docker 停止容器 docker stop 容器ID或容器名 docker 启动一个容器 -d:后台运行 -p:端口映 ...