C# task应用实例详解

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会减一。

运行结果如下:

到此这篇关于C# task应用实例的文章就介绍到这了,更多相关c#task应用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解C#中 Thread,Task,Async/Await,IAsyncResult的那些事儿

    说起异步,Thread,Task,async/await,IAsyncResult 这些东西肯定是绕不开的,今天就来依次聊聊他们 1.线程(Thread) 多线程的意义在于一个应用程序中,有多个执行部分可以同时执行:对于比较耗时的操作(例如io,数据库操作),或者等待响应(如WCF通信)的操作,可以单独开启后台线程来执行,这样主线程就不会阻塞,可以继续往下执行:等到后台线程执行完毕,再通知主线程,然后做出对应操作! 在C#中开启新线程比较简单 static void Main(string[]

  • c#异步task示例分享(异步操作)

    c# Task异步操作 复制代码 代码如下: using System;using System.Threading;using System.Threading.Tasks; namespace ConsoleApplication18{    class Program    {        static void Main(string[] args)        {            Func<string, string> _processTimeFunc = new Fun

  • windows下C#定时管理器框架Task.MainForm详解

    入住博客园4年多了,一直都是看别人的博客,学习别人的知识,为各个默默无私贡献自己技术总结的朋友们顶一个:这几天突然觉得是时候加入该队列中,贡献出自己微弱的力量,努力做到每个月有不同学习总结,知识学习的分享文章.以下要分享的是花了两天时间编写+测试的windows下C#定时管理器框架-Task.MainForm. 目的: 随着这五年在几个公司做不同职位的.net研发者,发现各个公司都或多或少会对接一些第三方合作的接口或者数据抓取功能,都是那种各个服务直接没有关联性功能,开发人员也可能不是一个人,使

  • C#中Task.Yield的用途深入讲解

    前言 最近在阅读 .NET Threadpool starvation, and how queuing makes it worse这篇博文时发现文中代码中的一种 Task 用法之前从未见过,在网上看了一些资料后也是云里雾里不知其解,很是困扰.今天在程序员节的大好日子里终于想通了,于是写下这篇随笔分享给大家,也过过专心写博客的瘾. 这种从未见过的用法就是下面代码中的 await Task.Yield() : static async Task Process() { await Task.Yi

  • C#利用Task实现任务超时多任务一起执行的方法

    前言 其实Task跟线程池ThreadPool的功能类似,不过写起来更为简单,直观.代码更简洁了,使用Task来进行操作.可以跟线程一样可以轻松的对执行的方法进行控制. 创建Task有两种方式,一种是使用构造函数创建,另一种是使用 Task.Factory.StartNew 进行创建. 如下代码所示 1.使用构造函数创建Task Task t1 = new Task(MyMethod); 2.使用Task.Factory.StartNew 进行创建Task Task t1 = Task.Fact

  • C# task应用实例详解

    Task的应用 ​Task的MSDN的描述如下: [Task类的表示单个操作不会返回一个值,通常以异步方式执行. Task对象是一种的中心思想基于任务的异步模式首次引入.NETFramework 4 中. 因为由执行工作Task对象通常以异步方式执行线程池线程上而不是以同步方式在主应用程序线程中,可以使用Status属性,并将IsCanceled, IsCompleted,和IsFaulted属性,以确定任务的状态. 大多数情况下,lambda 表达式用于指定该任务所执行的工作量. 对于返回值的

  • C#中Thread(线程)和Task(任务)实例详解

    目录 线程 一,使用Thread类启动线程和数据传输 二,线程池ThreadPool类 任务 一,创建并启动任务 二,连续任务 三,资源冲突问题 总结 线程 线程:对于所有需要等待的操作,例如移动文件,数据库和网络访问都需要一定的时间,此时就可以启动一个新的线程,同时完成其他任务.一个进程的多个线程可以同时运行在不同的CPU上或多核CPU的不同内核上. 一个应用程序启动时,会启动一个进程(应用程序的载体),然后进程会启动多个线程. 一,使用Thread类启动线程和数据传输 使用Thread类可以

  • Python 多线程实例详解

    Python 多线程实例详解 多线程通常是新开一个后台线程去处理比较耗时的操作,Python做后台线程处理也是很简单的,今天从官方文档中找到了一个Demo. 实例代码: import threading, zipfile class AsyncZip(threading.Thread): def __init__(self, infile, outfile): threading.Thread.__init__(self) self.infile = infile self.outfile =

  • Linux上的文件搜索命令实例详解

    locate 基础了解 在centos7上默认没有locate命令,需要先手动安装.安装步骤:http://www.cnblogs.com/feanmy/p/7676717.html locate命令搜索的后台数据库路径:/var/lib/mlocate/mlocate.db ls -hl /var/lib/mlocate total 1.2M -rw-r----- 1 root slocate 1.2M Oct 16 14:36 mlocate.db 更新数据库使用updatedb,配置文件为

  • Redis 实现队列原理的实例详解

    Redis 实现队列原理的实例详解 场景说明: ·用于处理比较耗时的请求,例如批量发送邮件,如果直接在网页触发执行发送,程序会出现超时 ·高并发场景,当某个时刻请求瞬间增加时,可以把请求写入到队列,后台在去处理这些请求 ·抢购场景,先入先出的模式 命令: rpush + blpop 或 lpush + brpop rpush : 往列表右侧推入数据 blpop : 客户端阻塞直到队列有值输出 简单队列: simple.php $stmt = $pdo->prepare('select id, c

  • Linux内存描述符mm_struct实例详解

    Linux对于内存的管理涉及到非常多的方面,这篇文章首先从对进程虚拟地址空间的管理说起.(所依据的代码是2.6.32.60) 无论是内核线程还是用户进程,对于内核来说,无非都是task_struct这个数据结构的一个实例而已,task_struct被称为进程描述符(process descriptor),因为它记录了这个进程所有的context.其中有一个被称为'内存描述符'(memory descriptor)的数据结构mm_struct,抽象并描述了Linux视角下管理进程地址空间的所有信息

  • Spark自定义累加器的使用实例详解

    累加器(accumulator)是Spark中提供的一种分布式的变量机制,其原理类似于mapreduce,即分布式的改变,然后聚合这些改变.累加器的一个常见用途是在调试时对作业执行过程中的事件进行计数. 累加器简单使用 Spark内置的提供了Long和Double类型的累加器.下面是一个简单的使用示例,在这个例子中我们在过滤掉RDD中奇数的同时进行计数,最后计算剩下整数的和. val sparkConf = new SparkConf().setAppName("Test").setM

  • Java多线程ForkJoinPool实例详解

    引言 java 7提供了另外一个很有用的线程池框架,Fork/Join框架 理论 Fork/Join框架主要有以下两个类组成. * ForkJoinPool 这个类实现了ExecutorService接口和工作窃取算法(Work-Stealing Algorithm).它管理工作者线程,并提供任务的状态信息,以及任务的执行信息 * ForkJoinTask 这个类是一个将在ForkJoinPool执行的任务的基类. Fork/Join框架提供了在一个任务里执行fork()和join()操作的机制

  • mysql的存储过程、游标 、事务实例详解

    mysql的存储过程.游标 .事务实例详解 下面是自己曾经编写过的mysql数据库存储过程,留作存档,以后用到的时候拿来参考. 其中,涉及到了存储过程.游标(双层循环).事务. [说明]:代码中的注释只针对当时业务而言,无须理会. 代码如下: DELIMITER $$ DROP PROCEDURE IF EXISTS `transferEmailTempData`$$ CREATE PROCEDURE transferEmailTempData(IN jobId VARCHAR(24)) BEG

  • Bootstrap与KnockoutJs相结合实现分页效果实例详解

    KnockoutJS是一个JavaScript实现的MVVM框架.非常棒.比如列表数据项增减后,不需要重新刷新整个控件片段或自己写JS增删节点,只要预先定义模板和符合其语法定义的属性即可.简单的说,我们只需要关注数据的存取. 一.引言 由于最近公司的系统需要改版,改版的新系统我打算使用KnockoutJs来制作Web前端.在做的过程中,遇到一个问题--如何使用KnockoutJs来完成分页的功能.在前一篇文章中并没有介绍使用KnockoutJs来实现分页,所以在这篇文章中,将补充用Knockou

随机推荐