C#Task任务详解及其使⽤⽅式
C#多线程编程笔记(4.3)-Task任务中实现取消选项
1.Task类介绍:
Task 类的表⽰单个操作不返回⼀个值,通常以异步⽅式执⾏。 Task 对象是⼀个的中⼼思想基于任务的异步模式⾸次引⼊.NET Framework 4 中。因为由执⾏⼯作 Task 对象通常以异步⽅式执⾏在线程池线程上⽽不是以同步⽅式在主应⽤程序线程,您可以使⽤ Status 属性,以及IsCanceled, ,IsCompleted, ,和 IsFaulted 属性,以确定任务的状态。⼤多数情况下,lambda 表达式⽤于指定的任务是执⾏的⼯作。
对于返回值的操作,您使⽤ Task 类。
任务Task和线程Thread的区别:
1、任务是架构在线程之上的,也就是说任务最终还是要抛给线程去执⾏。
2、任务跟线程不是⼀对⼀的关系,⽐如开10个任务并不是说会开10个线程,这⼀点任务有点类似线程池,但是任务相⽐线程池有很⼩的开销和精确的控制。
Task和Thread⼀样,位于System.Threading命名空间下!
⼀、创建Task
秦国灭六国顺序Task 类还提供了构造函数对任务进⾏初始化,但的未计划的执⾏。出于性能原因, Task.Run 或 TaskFactory.StartNew(⼯⼚创建)⽅法是⽤于创建和计划计算的任务的⾸选的机制,但对于创建和计划必须分开的⽅案,您可以使⽤的构造函数(new⼀个出来),然后调
⽤ Task.Start ⽅法来计划任务,以在稍后某个时间执⾏。
//第⼀种创建⽅式,直接实例化:必须⼿动去Start
var task1 = new Task(() =>
{
//TODO you code
});
task1.Start();
//第⼆种创建⽅式,⼯⼚创建,直接执⾏
var task2 = Task.Factory.StartNew(() =>
{
//TODO you code
});
⼆、Task的简略⽣命周期:
⽅法名说明
Created表⽰默认初始化任务,但是“⼯⼚创建的”实例直接跳过。
WaitingToRun这种状态表⽰等待任务调度器分配线程给任务执⾏。
RanToCompletion任务执⾏完毕。
//查看Task中的状态
var task1 = new Task(() =>
{
Console.WriteLine("Begin");
System.Threading.Thread.Sleep(2000);
Console.WriteLine("Finish");
});
Console.WriteLine("Before start:" + task1.Status);
task1.Start();
Console.WriteLine("After start:" + task1.Status);
task1.Wait();
Console.WriteLine("After Finish:" + task1.Status);
Console.Read();
三、Task的任务控制:Task最吸引⼈的地⽅就是他的任务控制了,你可以很好的控制task的执⾏顺序,让多个task有序的⼯作
⽅法名说明
Task.Wait task1.Wait();就是等待任务执⾏(task1)完成,task1的状态变为Completed。
Task.WaitAll待所有的任务都执⾏完成:
Task.WaitAny发同Task.WaitAll,就是等待任何⼀个任务完成就继续向下执⾏
Task.ContinueWith第⼀个Task完成后⾃动启动下⼀个Task,实现Task的延续
CancellationTokenSource通过cancellation的tokens来取消⼀个Task。
⽅法名说明
下⾯详细介绍⼀下上⾯的⼏个⽅法:
1、Task.Wait
task1.Wait();就是等待任务执⾏(task1)完成,task1的状态变为Completed。
2、Task.WaitAll外地人上海买房
看字⾯意思就知道,就是等待所有的任务都执⾏完成:
{
Task.WaitAll(task,N)
Console.WriteLine("All task finished!");
}
即当task,task2,task3…N全部任务都执⾏完成之后才会往下执⾏代码(打印出:“All task finished!”)
3、Task.WaitAny
这个⽤发同Task.WaitAll,就是等待任何⼀个任务完成就继续向下执⾏,将上⾯的代码WaitAll替换为WaitAny
{
Task.WaitAny(task,N)
Console.WriteLine("Any task finished!");
}
即当task,task2,task3…N任意⼀个任务都执⾏完成之后就会往下执⾏代码(打印出:” Any task finished!”)
4、Task.ContinueWith
就是在第⼀个Task完成后⾃动启动下⼀个Task,实现Task的延续,下⾯我们来看下他的⽤法,编写如下代码:
  static void Main(string[] args)
{
var task1 = new Task(() =>
{
Console.WriteLine("Task 1 Begin");
System.Threading.Thread.Sleep(2000);
Console.WriteLine("Task 1 Finish");不过是一城山水一场空
});
var task2 = new Task(() =>
{
Console.WriteLine("Task 2 Begin");
System.Threading.Thread.Sleep(3000);
Console.WriteLine("Task 2 Finish");
});
task1.Start();
task2.Start();
var result = task1.ContinueWith<string>(task =>
{
Console.WriteLine("task1 finished!");
return "This is task result!";
});
Console.WriteLine(result.Result.ToString());
Console.Read();
什么食物可以减肥}
可以看到,task1完成之后,开始执⾏后⾯的内容,并且这⾥我们取得task的返回值。
5、Task的取消
前⾯说了那么多Task的⽤法,下⾯来说下Task的取消,⽐如我们启动了⼀个task,出现异常或者⽤户
点击取消等等,我们可以取消这个任务。如何取消⼀个Task呢,我们通过cancellation的tokens来取消⼀个Task。在很多Task的Body⾥⾯包含循环,我们可以在轮询的时候判断IsCancellationRequested属性是否为True,如果是True的话就return或者抛出异常,抛出异常后⾯再说,因为还没有说异常处理的东西。
下⾯在代码中看下如何实现任务的取消,代码如下:
    var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
var task = Task.Factory.StartNew(() =>
{
for (var i = 0; i < 1000; i++)
{
System.Threading.Thread.Sleep(1000);
if (token.IsCancellationRequested)
{
Console.WriteLine("Abort mission success!");
return;
}
}
}, token);
token.Register(() =>
{
Console.WriteLine("Canceled");
});
Console.WriteLine("Press enter to ");
Console.ReadKey();
tokenSource.Cancel();
这⾥开启了⼀个Task,并给token注册了⼀个⽅法,输出⼀条信息,然后执⾏ReadKey开始等待⽤户输⼊,⽤户点击回车后,执⾏tokenSource.Cancel⽅法,取消任务。
注:
1. 因为任务通常运⾏以异步⽅式在线程池线程上,创建并启动任务的线程将继续执⾏,⼀旦该任务已实例化。在某些情况下,当调⽤线
程的主应⽤程序线程,该应⽤程序可能会终⽌之前任何任务实际开始执⾏。其他情况下,应⽤程序的逻辑可能需要调⽤线程继续执⾏,仅当⼀个或多个任务执⾏完毕。您可以同步调⽤线程的执⾏,以及异步任务它启动通过调⽤ Wait ⽅法来等待要完成的⼀个或多个任务。若要等待完成⼀项任务,可以调⽤其 Task.Wait ⽅法。调⽤ Wait ⽅法将⼀直阻塞调⽤线程直到单⼀类实例都已完成执⾏。
using System;
using System.Threading.Tasks;
using System.Threading;
namespace 实现取消选项
{
class Program
{
static void Main(string[] args)
{
var cts = new CancellationTokenSource();
var longTask = new Task<int>(() => TaskMethod("Task 1", 10, cts.Token), cts.Token);
Console.WriteLine(longTask.Status);
cts.Cancel();
Console.WriteLine(longTask.Status);
Console.WriteLine("First task has been cancelled before execution");
cts = new CancellationTokenSource();
longTask = new Task<int>(() => TaskMethod("Task 2", 10, cts.Token), cts.Token);
longTask.Start();
for (int i = 0; i < 5; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine(longTask.Status);
}
cts.Cancel();
for (int i = 0; i < 5; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine(longTask.Status);
}
Console.WriteLine("A task has been completed with result {0}.", longTask.Result);
Console.ReadKey();
}
private static int TaskMethod(string name,int seconds,CancellationToken token)
{
认识大自然手抄报内容Console.WriteLine("Task {0} is running on a thread id {1},Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsThreadPoolThread);
for (int i = 0; i < seconds; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(1));
if (token.IsCancellationRequested)
{
Console.WriteLine("Cancel Task {0} is running on a thread id {1},Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsThreadPoolThread);
本科报考return -1;
}
}
return 42 * seconds;        }
}
}