1、创建任务的四种方式:
第一种方式是实例化TaskFactory类,在其中把TaskMethod方法传递给StartNew方法,就会立即启动任务。
var tf = new TaskFactory();
var t1 = tf.StartNew(TaskMethod, "using a task factroy");
第二种是使用Task的静态属性Factory来访问TaskFactory,以及调用StartNew()方法。
var t2 = Task.Factory.StartNew(TaskMethod, "factroy via a task");
第三种是使用Task类的构造函数,调用Start()方法来启动任务
var t3 = new Task(TaskMethod, "using a task constructor and start");
t3.Start();
第四种调用Task的run方法,立即启动任务。传递Action类型的lambda表达式并在其实现中使用参数
Task t4 = Task.Run(()=>TaskMethod("using the run method"));
2、同步任务
任务不一定要使用线程池中的线程,也可以使用其他线程。任务可以同步运行,以相同的线程为主调线程。这里TaskMethod方法首先在主线程上直接调用,然后在新的创建的Task上调用。下面的例子中:主线程是一个前台线程,没有任务ID也不是线程池中的线程。调用RunSynchronously方法时,会使用相同的线程作为主调线程,但是如果以前没有创建任务,就会创建一个任务。
public static void RunSynchronousTask()
{
TaskMethod("just the main thread");
var t1 = new Task(TaskMethod,"run sync");
t1.RunSynchronously();
}
3、使用单独线程的任务
如果任务的代码应该长时间运行,就应该使用TaskCreationOptions.LongRunning告诉任务调度创建一个新的线程,而不是使用线程池中的线程。此时,线程可以不由线程池管理。当线程来自线程池时,任务调度器可以决定等待已经运行的任务完成,然后使用这个线程,而不是在线程池中建一个新线程。对于长时间运行的线程,任务调度器会立即知道等待他们完成不是明智的做法。
public static void LongRunningTask()
{
var t1 = new Task(TaskMethod,"Long running",TaskCreationOptions.LongRunning);
t1.Start();
}
4、取消架构
取消架构基于协作行为,它不是强制性的。长时间运行的任务会检查它是否被取消,并返回控制权。支持取消的方法接受一个CancellationToken参数。这个类定义了IsCancellationRequested属性,其中长时间运行的操作可以检查它是否终止。长时间运行的操作检查取消的其他方式有:取消标记时,使用标记的WaitHandle属性,或者使用Registed()方法。Registed()方法接受Action和ICancelableOperation类型的参数。Action委托的方法在取消标记时调用。
4.1、 Parallel.For()方法的取消
var cts = new CancellationTokenSource();
cts.Token.Register(() => Console.WriteLine("**********token canceled***********"));
cts.CancelAfter(500);
try
{
ParallelLoopResult result = Parallel.For(0, 100, new
ParallelOptions()
{
CancellationToken = cts.Token,
},
x=> {
Console.WriteLine("loop {0} started",x);
int sum = 0;
for (int i = 0; i < 100; i++)
{
Thread.Sleep(2);
sum += i;
}
Console.WriteLine("loop {0} finished",x);
});
}
catch(OperationCanceledException ex)
{
Console.WriteLine(ex.Message);
}
4.2任务的取消
同样的操作也可用于任务。运行应用程序,可以看到任务启动了,运行几个循环,并获得了取消请求。之后取消任务,并抛出TaskCanceledException异常,他是从方法调用ThrowIfCancellationRequested()中启动的,调用者等待任务时,会捕获AggregateException异常,它包含内部异常TaskCanceledException。
var cts = new CancellationTokenSource();
cts.Token.Register(() => Console.WriteLine("**********token canceled***********"));
cts.CancelAfter(500);
Task t1 = Task.Run(()=> {
Console.WriteLine("in task");
for (int i = 0; i < 20; i++)
{
Thread.Sleep(100);
CancellationToken token = cts.Token;
if(token.IsCancellationRequested)
{
Console.WriteLine("cancelling was requested,cancelling from within the task");
token.ThrowIfCancellationRequested();
break;
}
Console.WriteLine("in loop");
}
Console.WriteLine( "task finished without cancellation");
},cts.Token);
try
{
t1.Wait();
}
catch(AggregateException ex)
{
Console.WriteLine( "execption:{0},{1}",ex.GetType().Name,ex.Message);
foreach (var item in ex.InnerExceptions)
{
Console.WriteLine( "inner exception:{0},{1} ",ex.InnerException.GetType().Name,ex.InnerException.Message);
}
}