本节将展示如何设置相互依赖的任务。我们将学习如何创建一个任务,使其在父任务完成后才会被运行。另外,将探寻为非常短暂的任务节省线程开销的可能性。
class Program { static void Main(string[] args) { var firstTask = new Task<int>(() => TaskMethod("First Task", 3)); var secondTask = new Task<int>(() => TaskMethod("Second Task", 2)); firstTask.ContinueWith(//给第一个任务设置后续操作,在第一个任务完成后执行 t => Console.WriteLine("The first answer is {0}. Thread id {1}, is thread pool thread: {2}", t.Result, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread), TaskContinuationOptions.OnlyOnRanToCompletion); firstTask.Start(); secondTask.Start(); Thread.Sleep(TimeSpan.FromSeconds(4));//主线程----等待上面两个任务的完成,4秒应该足够执行完上面2个操作
//如果注释掉以上语句,主线程直接执行下面的语句,则第二个任务的后续操作会放到线程池中执行
/* 设置第二个任务的后续操作,TaskContinuationOptions.ExecuteSynchronously设置为同步执行,
* 如果上面不等待4秒,后续操作将放到线程池中等待第二个任务执行完成后执行;如果等待4秒,即等待
* 第二个任务的完成,则后续操作被放到主线程中执行。因为后续操作非常短暂,所以放到主线程中比放到
* 线程池中运行快。
* TaskContinuationOptions.OnlyOnRanToCompletion指示第二个任务完成后才会安排后续任务。
*/
Task continuation = secondTask.ContinueWith(//第二个任务运行另一个后续操作
t => Console.WriteLine("The second answer is {0}. Thread id {1}, is thread pool thread: {2}",
t.Result, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread),
TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously);
continuation.GetAwaiter().OnCompleted(//给continuation任务继续安排后续任务
() => Console.WriteLine("Continuation Task Completed! Thread id {0}, is thread pool thread: {1}",
Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread));
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine();
//以下为父子任务线程有关
/* 子任务必须在父任务运行时创建,并且正确的附加给父任务!
* TaskContinuationOptions.AttachedToParent把子任务添加到父任务,只有所有子任务都完成,父任务才能完成。
*/
firstTask = new Task<int>(() =>//创建新任务
{
//通过提供AttachedToParent选项来来运行一个所谓的子任务
var innerTask = Task.Factory.StartNew(() => TaskMethod("Second Task", 5), TaskCreationOptions.AttachedToParent);
innerTask.ContinueWith(t => TaskMethod("Third Task", 2), TaskContinuationOptions.AttachedToParent);
return TaskMethod("First Task", 2);
});
firstTask.Start();
//以下语句可以验证父任务是否在子任务全部结束后完成
while (!firstTask.IsCompleted)
{
Console.WriteLine(firstTask.Status);
Thread.Sleep(TimeSpan.FromSeconds(0.5));
}
Console.WriteLine(firstTask.Status);
Thread.Sleep(TimeSpan.FromSeconds(10));
}
static int TaskMethod(string name, int seconds)
{
Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
Thread.Sleep(TimeSpan.FromSeconds(seconds));
return 42 * seconds;
}
}