启动任务
怎样启动一个任务?代码中我们首先要添加using System.Threading.Tasks;引用。我们可以使用TaskFactory类或Task类的构造函数和Start()方法。在启动任务时,会创建Task类的一个实例。首先我们看一段代码using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Action<object> action = (object obj) =>
{
for (int i = 0; i < 10; i ++ )
{
// 任务是后台线程,所以这里是无序执行的
Console.WriteLine("Task={0}, obj={1}, Thread={2}, Pos={3}", Task.CurrentId, obj.ToString(), Thread.CurrentThread.ManagedThreadId, i.ToString());
}
};
TaskFactory tf = new TaskFactory();
Task t1 = tf.StartNew(action, "第一种方法");
Task t2 = Task.Factory.StartNew(action, "第二种方法");
Task t3 = new Task(action,"第三种方法");
t3.Start();
Task t4 = new Task(action, TaskCreationOptions.PreferFairness);
t4.Start();
Thread.Sleep(1000);
Console.WriteLine("---------end------------");
}
}
}
在上面代码中。我们可以看到启动新任务的不同方式:
1、 第一种使用实例化的TaskFactory类,把NewTask()方法传递给StartNew()方法,任务就会立即启动。
2、 第二种方式是使用Task类的构造函数,实例化任务时,任务不会立即启动,此时任务的状态为Created。然后调用Task类的Start()方法来启动任务,还可以调用RunSynchronously()方法来启动任务。
默认情况下,任务是异步运行的。。。
使用Task类的构造函数和TaskFactory类的StartNew()方法时,都可以传递TaskCreationOptions枚举中的值。
成员名称 |
说明 |
None |
指定应使用默认行为。 |
PreferFairness |
提示 TaskScheduler 以一种尽可能公平的方式安排任务,这意味着较早安排的任务将更可能较早运行,而较晚安排运行的任务将更可能较晚运行。 |
LongRunning |
指定某个任务将是运行时间长、粗粒度的操作。 它会向 TaskScheduler 提示,过度订阅可能是合理的。 |
AttachedToParent |
指定将任务附加到任务层次结构中的某个父级。 |
例如:如果任务使用子任务创建了其它任务,子任务就优先于其它任务。当然它们不会排在线程池的最后。如果这些任务应以公平的方式与所有其它任务一起处理,就设置选项为PerferFainress,如下所示
Task t4 = new Task(NewTask,TaskCreationOptions.PreferFairness);
t4.Start();
创建连续的任务
通过创建任务,我们可以指定在一个任务完成过后,开始运行另外一个指定的任务。任务处理程序不带参数或者带一个Object类型的参数。连续处理程序有一个Task类型的参数,可以访问起始任务的相关信息。
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Task t1 = new Task(FirstTask);
Task t2 = t1.ContinueWith(SecondTask);
t1.Start();
}
static void FirstTask()
{
Console.WriteLine("第一个任务开始: task=" + Task.CurrentId);
}
static void SecondTask(Task task)
{
Console.WriteLine("任务{0}完成", task.Id);
Console.WriteLine("第二个任务开始:TaskID:{0}", Task.CurrentId);
Console.WriteLine("清理工作......");
}
}
}
连续的任务通过在任务上调用ContinueWith()方法来定义。t1.ContinueWith(SecondTask)方法表示,调用SecondTask()方法的新任务应该在t1任务完成后立即启动过,在第一个任务结束时,还可以启动多个任务。无论前一个任务是如何结束的,前面的连续任务总是在前面一个任务结束时启动,使用TaskContinueOptions枚举中的值可以指定连续任务只有在起始任务成功或者失败时启动,TaskContinueOptions的枚举值有
成员名称 |
说明 |
None |
Default = "Continue on any, no task options, run asynchronously" 指定应使用默认行为。 默认情况下,完成前面的任务之后将安排运行延续任务,而不考虑前面任务的最终 TaskStatus。 |
PreferFairness |
提示 TaskScheduler 以一种尽可能公平的方式安排任务,这意味着较早安排的任务将更可能较早运行,而较晚安排运行的任务将更可能较晚运行。 |
LongRunning |
指定某个任务将是运行时间长、粗粒度的操作。 它会向 TaskScheduler 提示,过度订阅可能是合理的。 |
AttachedToParent |
指定将任务附加到任务层次结构中的某个父级。 |
NotOnRanToCompletion |
指定不应在延续任务前面的任务已完成运行的情况下安排延续任务。 此选项对多任务延续无效。 |
NotOnFaulted |
指定不应在延续任务前面的任务引发了未处理异常的情况下安排延续任务。 此选项对多任务延续无效。 |
NotOnCanceled |
指定不应在延续任务前面的任务已取消的情况下安排延续任务。 此选项对多任务延续无效。 |
OnlyOnRanToCompletion |
指定只应在延续任务前面的任务已完成运行的情况下才安排延续任务。 此选项对多任务延续无效。 |
OnlyOnFaulted |
指定只应在延续任务前面的任务引发了未处理异常的情况下才安排延续任务。 此选项对多任务延续无效。 |
OnlyOnCanceled |
指定只应在延续任务前面的任务已取消的情况下才安排延续任务。 此选项对多任务延续无效。 |
ExecuteSynchronously |
指定应同步执行延续任务。 指定此选项后,延续任务将在导致前面的任务转换为其最终状态的相同线程上运行。 如果在创建延续任务时已经完成前面的任务,则延续任务将在创建此延续任务的线程上运行。 只应同步执行运行时间非常短的延续任务。 |
摘录至MSDN:http://technet.microsoft.com/zh-CN/library/system.threading.tasks.taskcontinuationoptions
任务的层次结构
利用任务的连续性,就可以在一个任务结束后启动另外一个任务。一个任务启动一个新任务时,就启动了一个父/子层次结构,如下所示:
using System;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleLayer
{
class Program
{
static void Main(string[] args)
{
Task parent = new Task(ParentTask);
parent.Start();
Thread.Sleep(1000);
Console.WriteLine("父任务的状态:{0}",parent.Status);
Thread.Sleep(4000);
Console.WriteLine("父任务的状态:{0}",parent.Status);
}
public static void ParentTask()
{
Console.WriteLine("父任务{0}正在运行......",Task.CurrentId);
Task child = new Task(ChildTask);
child.Start();
Console.WriteLine("父任务启动了子任务");
Thread.Sleep(1000);
}
static void ChildTask()
{
Console.WriteLine("子任务{0}正在运行......",Task.CurrentId);
Thread.Sleep(3000);
Console.WriteLine("子任务执行完成。");
}
}
}
运行结果:
如果父任务在子任务之前结束,父任务的状态就会显示为WatingForChildrenToComplete。子任务的任务完成后,父任务的状态就是RanToCompletion。
原文出自:http://www.soaspx.com/dotnet/csharp/csharp_20120618_9290.html