C# task应用实例详解
作者:Kiba518 发布时间:2023-01-22 05:23:53
Task的应用
Task的MSDN的描述如下:
【Task类的表示单个操作不会返回一个值,通常以异步方式执行。
Task对象是一种的中心思想基于任务的异步模式首次引入.NETFramework 4 中。
因为由执行工作Task对象通常以异步方式执行线程池线程上而不是以同步方式在主应用程序线程中,可以使用Status属性,并将IsCanceled, IsCompleted,和IsFaulted属性,以确定任务的状态。
大多数情况下,lambda 表达式用于指定该任务所执行的工作量。
对于返回值的操作,您使用Task类。】
我对于Task的理解是这样的,Task是FrameWork4引进的新功能,他和ConCurrent命名空间一起被引进,用来替代Thread的使用。
根据我的使用,个人觉得,他确实比Thead的功能要丰富一些。
下面我们一起看一个最简单的例子:
using System;
using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;namespace TaskConsole
{ class Program
{ static void Main(string[] args)
{ //当前线程标识 Console.WriteLine(Thread.CurrentThread.GetHashCode());
Task task = new Task(run);
Console.WriteLine("任务标识:" + task.GetHashCode() + ",状态:" + task.Status);//状态 task.Start();
Console.WriteLine("任务标识:" + task.GetHashCode() + ",状态:" + task.Status);//状态 //任务完成后执行新任务
Action ation = new Action(taskStart);
task.ContinueWith(ation);
Console.Read();
} public static void taskStart(Task task)
{
task = new Task(run);
task.Start(); //如果注释上面两句话,则任务标识为 task.ContinueWith(ation)中task的任务
Console.WriteLine("任务标识:" + task.GetHashCode() + ",状态:" + task.Status + ",当前线程:" + Thread.CurrentThread.GetHashCode());//状态
} public static void run()
{
Console.WriteLine("this is run");
}
}
}
一,task.GetHashCode(),是获取Task实例的唯一标识,每个Task都不一样。
测试发现,Task.GetHashCode()并不等于Thread.CurrentThread.GetHashCode()。
二,task.ContinueWith(),是任务结束后继续执行任务的方法,传一个Action,当任务结束后,触发该Action。
任务刚new出来的时候,task就又状态了,是Created,一但运行了,状态就是WaitingToRun。
运行结果如下:
根据MSDN的说明,Task.State是获取TaskState的枚举值,其枚举值代表的意义如下
|Canceled |该任务已通过对其自身的 CancellationToken 引发 OperationCanceledException 对取消进行了确认,此时该标记处于已发送信号状态;或者在该任务开始执行之前,已向该任务的 CancellationToken 发出了信号。 有关更多信息,请参见任务取消。
| Created |该任务已初始化,但尚未被计划。
| Faulted |由于未处理异常的原因而完成的任务。
| RanToCompletion |已成功完成执行的任务。
| Running |该任务正在运行,但尚未完成。
| WaitingForActivation |该任务正在等待 .NET Framework 基础结构在内部将其激活并进行计划。
| WaitingForChildrenToComplete |该任务已完成执行,正在隐式等待附加的子任务完成。
| WaitingToRun |该任务已被计划执行,但尚未开始执行。
任务嵌套
任务嵌套就是指在一个任务中又创建了一个任务。
而新建的任务就是子任务。在没有特殊声明的情况下,父子任务是一起运行的。
如SimpleNestedTask方法。
父子任务关联需要在创建子任务的时候,增加参数TaskCreationOptions.AttachedToParent。
将父子任务关联起来,此时父任务将等待子任务结束,才会完成。
如果使用Task创建任务,不需要使用TaskCreationOptions.AttachedToParent参数,因为只要父任务使用了子任务的返回结果,父任务自然就会等待子任务完成。
public class Program
{
static void Main(string[] args)
{
WaitForSimpleNestedTask();
Console.WriteLine("=====================================================");
SimpleNestedTask();
Thread.SpinWait(600000);//等待SimpleNestedTask结束 再运行
Console.WriteLine("=====================================================");
//SimpleNestedTaskAttachedToParent();
Console.Read();
}
static void WaitForSimpleNestedTask()
{
var outer = Task.Factory.StartNew(() =>
{
Console.WriteLine("Outer1 task executing.");
var nested = Task.Factory.StartNew(() =>
{
Console.WriteLine("Nested1 task starting.");
Thread.SpinWait(5000000);
Console.WriteLine("Nested1 task completing.");
return 42;
});
return nested.Result;
return 1;
});
Console.WriteLine("Outer1 has returned {0}.", outer.Result);
}
static void SimpleNestedTask()
{
var parent = Task.Factory.StartNew(() =>
{
Console.WriteLine("Outer2 task executing.");
var child = Task.Factory.StartNew(() =>
{
Console.WriteLine("Nested2 task starting.");
Thread.SpinWait(500000);
Console.WriteLine("Nested2 task completing.");
});
});
parent.Wait();
Console.WriteLine("Outer2 has completed.");
}
static void SimpleNestedTaskAttachedToParent()
{
var parent = Task.Factory.StartNew(() =>
{
Console.WriteLine("Outer3 task executing.");
var child = Task.Factory.StartNew(() =>
{
Console.WriteLine("Nested3 task starting.");
Thread.SpinWait(500000);
Console.WriteLine("Nested3 task completing.");
}, TaskCreationOptions.AttachedToParent);
});
parent.Wait();
Console.WriteLine("Outer has completed.");
}
ConCurrent的线程安全的
因为,MSDN将在System.Collections.Concurrent命名空间下的集合,都称为线程安全的集合。
线程安全可以理解为可以被多个线程同时使用的集合,而且同时使用的时候是该集合的值是准确的。
下面举一个使用线程安全集合的例子,使用的是BlockingCollection。
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ParallelConsole
{
class Program
{
//定义集合大小为51个,也可以不定义大小
static BlockingCollection blocking = new BlockingCollection(51);
static void Main(string[] args)
{
blocking = new BlockingCollection();
Console.WriteLine("当前blocking为:" + blocking.IsCompleted + "设置了集合大小count一样是0,blocking.Count:" + blocking.Count());
//当前线程标识
Console.WriteLine(Thread.CurrentThread.GetHashCode());
for (int i = 0; i < 3; i++)
{
////如果添加到第3个,就设置添加完成,这时在添加就会抛异常
//if (i == 3)
//{
// blocking.CompleteAdding();
//}
Action action = new Action(run);
Task task = new Task(action,i);
task.RunSynchronously();
}
Console.WriteLine("设置添加完成前:" + blocking.IsAddingCompleted);
//设置添加完成后
blocking.CompleteAdding();
Console.WriteLine("设置添加完成后:" + blocking.IsAddingCompleted);
#region 同步取 取3个
//for (int i = 0; i < 3; i++)
//{
// Action actionTake = new Action(take);
// actionTake();
//}
#endregion
//并发读取
#region 并发步取 取3个
//blocking.IsCompleted 只有当集合被添加进内容,然后又都被取光了以后,他才会等于ture,否则都是false
//当IsCompleted为ture时,就不能再取了否则会抛异常
//同时取,结果是
//blocking:0
//blocking:2
//blocking:1
if (!blocking.IsCompleted)//如果集合没取光
{
Action actionTake2 = new Action(take);
Parallel.Invoke(actionTake2, actionTake2, actionTake2);
}
#endregion
Console.WriteLine("当前blocking为:" + blocking.IsCompleted + ",blocking数量为:" + blocking.Count());
//数据被取光了以后, blocking.Count()为0
Console.Read();
}
public static void take()
{
//同步取,blocking.Count()会真实的表现,而异步取,Count是不准确的,因为我取count的时候,可能集合已经又被取出数据了,测试10次肯定会出现不真实的情况
Console.WriteLine("blocking:" + blocking.Take() + ",blocking数量为:" + blocking.Count());
}
public static void run(object i)
{
int currentI = int.Parse(i.ToString());
blocking.TryAdd(currentI);
}
}
}
Parallel
Parallel.Invoke(),并发调用Action,可以传多个Action,也可以传一个Action数据组。
Task
Task(Action,object),这是Task的构造方法,接收Action,object是Action的参数,。
task.RunSynchronously(),他是同步运行任务计划用的,同时他和task.Start()一样,也可以启动线程。
BlockingCollection集合
属性一:IsCompleted,他是表示集合是否有数据,只有当集合被添加进内容,然后又都被取光了以后,他才会等于ture,否则都是false。
属性一:BlockingCollection.IsAddingCompleted,表示是否添加完成。针对blocking.CompleteAdding()的使用,当调用了该方法IsAddingCompleted就为true。
方法一:BlockingCollection.blocking.CompleteAdding(),设置IsAddingCompleted用的。
方法二:BlockingCollection.Add,添加一个实体
方法三:BlockingCollection.TryAdd,添加一个实体,我这里用的是这个方法,区别是,如果添加重复项,他会引发InvalidOperationException这个异常。
方法四:BlockingCollection.Take,从集合中取一个值,注意,是真的取出来,取出来后,BlockingCollection.cout会减一。
运行结果如下:
来源:https://www.imooc.com/article/270174


猜你喜欢
- 1.什么是thread当我们提及多线程的时候会想到thread和threadpool,这都是异步操作,threadpool其实就是threa
- 一.MyBatis简介 一说起对象关系映射框架,大家第一时间想到的肯定是Hibernate。Hibern
- c语言关闭socket的两种方式一、shutdown()#include<sys/socket.h>int shutdown(i
- 前言: 有时候我们需要实现长按选择文字功能,比如阅读器一般都有这个功能,有时候某个自定义控件上可能就有这种需求,如何实现呢?正好最近还算闲,
- 自定义starter yaml提示失效问题问题场景在自定义starter后,必不可少会有properties配置参数需要指定,而在有时又不知
- Springboot内部提供的事务管理器是根据autoconfigure来进行决定的。比如当使用jpa的时候,也就是pom中加入了sprin
- 实现步骤:1.实现整个鼠标框选的几个事件(down、move、up),当鼠标点下记录鼠标框选的起点,鼠标抬起结束操作。2.以鼠标框选过程中获
- 宏定义与预处理命令预处理阶段:处理宏定义与预处理命令;编译期:检查代码,分析语法、语义等,最后生成.o或.obj文件;链接期:链接所有的.o
- 本文实例为大家分享了Android自定义View画天气预报折线图的具体代码,供大家参考,具体内容如下效果图如下:刚开始尝试用第三方画曲线的框
- 一、Spring能做什么?Spring的主要目的是使J2EE易用和促进好编程习惯。倒置控制容器 Spring的设计核心是 org.sprin
- IO流Java中IO流分为两种,字节流和字符流,顾名思义字节流就是按照字节来读取和写入的,字符刘是按照字符来存取的;常用的文件读取用的就是字
- 本文实例讲述了Android编程实现ListView滚动提示等待框功能。分享给大家供大家参考,具体如下:其实原理很简单,只需要设置监听lis
- 前提: 可以参考文章 SpringBoot 接入 SparkSpringBoot 已经接入 Spark已配置 JavaSparkContex
- 🍅1.注解JUnit提供了非常强大的注解功能,通过@Test注解修饰到方法上,该方法就变为了一个测试方法,执行当前类时,会自动的执行该类下所
- 今天一个读者问我关于Android通过调用Webservice实现天气预报这篇文章的源码下载后出现的错误Could not find cla
- 本文实例讲述了Android编程单选项框RadioGroup用法。分享给大家供大家参考,具体如下:今天介绍的是RadioGroup 的组事件
- 前言在工作中遇到这样一个问题:开发过程中将数据库的账号、密码等信息配置在了一个单独的properties配置文件中(使用明文)。但运维人员要
- 首先要引用一下类库:using Ionic.Zip;这个类库可以到网上下载。下面对类库使用的封装方法:得到指定的输入流的ZIP压
- 现在的应用在注册登录或者修改密码中都用到了短信验证码,那在android中是如何实现获取短信验证码并自动填写的呢?首先,需要要在manife
- 前言关键字Final不仅可以用来修饰变量,而且对类及其方法的继承也有很大的影响,本文将从类与方法两个方面介绍final关键字的功能。Fina