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
猜你喜欢
- 在上面的例子中多次使用到了Thread类的join方法。我想大家可能已经猜出来join方法的功能是什么了。对,join方法的功能就是使异步执
- 问题描述在开发批量删除功能时,往往都是多条数据,所以前台需要传一个数组给后台,但是怎么在URL中绑定一个数组,同时在后台用@PathVari
- IDEA maven没有dependenciesIDEA导入新项目没有dependencies跟plugins如图:解决办法网上方法很多,重
- webservice的POST和GET请求调用POST请求1.发送请求import java.io.DataOutputStream;imp
- 寻找到application.yml的读取的操作。从spring.factories 中查看到# Application Listeners
- 前一段时间粗略看了一下《深入Java虚拟机 第二版》,可能是因为工作才一年的原因吧,看着十分的吃力。毕竟如果具体到细节的话,Java虚拟机涉
- 一. SpringBoot中实现Session共享1. 创建web项目我们按照之前的经验,创建一个web程序,并将之改造成Spring Bo
- 一.导入Netty依赖<dependency> <groupId>io.netty</group
- 最近开发项目中,有个在屏幕上任意拖动的悬浮窗功能,其实就是利用 WindowManager的api来完成这个需求,具体的实现的功能如下:1.
- 前言这篇文章的内容基于对Spring Security 认证流程的理解,如果你不了解,可以读一下这篇文章:Spring Security 认
- servlet实现文件上传,预览,下载和删除,供大家参考,具体内容如下一、准备工作:1.1 文件上传插件:uploadify;1.2 文件上
- 在线程间通信方式中,我们了解到可以使用Semaphore信号量来实现线程间通信,Semaphore支持公平锁和非公平锁,Semaphore底
- 背景接上文《失踪人口回归,mybatis-plus 3.3.2 发布》[1] ,提供了一个非常实用的功能 「数据安全保护」 功能,不仅支持数
- Step1: 安装JDK并配置环境变量;Step2: 安装Gradle进入点击打开链接官网首页点击install gra
- Java Tess4J实现图像识别最近需要用Java做一个图像识别的东西,查了一些资料,在此写一个基于Tess4J的教程,方便其他人参考和使
- 前言回想写过的图书管理系统、租房系统、电影院卖票系统都是基于原生的JavaSE、OOP,没有用到任何框架,在层与层的关系中一个类要想获得与其
- 1、需要引入依赖<dependency> &l
- 本文实例讲述了C#使用linq查询大数据集的方法。分享给大家供大家参考。具体如下:using System;using System.Col
- 目录LinkedHashMap 实现继承 LinkedHashMap组合 LinkedHashMap链表 + HashMap 实现LRU,即
- 一、Shiro简介:Apache Shiro是一个Java的安全(权限)框架。Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在J