近来在学习Eugene Agafonov编写的《C#多线程编程实战》(译),做些笔记也顺便分享一下^-^
本节将展示如何设置相互依赖的任务。我们将学习如何创建一个任务,使其在父任务完成后才会被运行。
using System;
using System.Threading.Tasks;
using System.Threading;
namespace 组合任务
{
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));
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(
() => Console.WriteLine("Cotinuation Task Completed!" +
"Thread id {0},is thread pool thread: {1}",
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsThreadPoolThread));
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine();
firstTask = new Task<int>(() =>
{
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));
Console.ReadKey();
}
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;
}
}
}
程序运行结果如下:
当主程序启动时,我们创建了两个任务,并为第一个任务设置了一个后续操作(continuation,一个代码块,会在当前任务完成后运行)。然后启动这两个任务并等待4秒,这个时间足够两个任务完成。然后给第二个任务运行另一个后续操作,并通过指定TaskContinuationOptions.ExecuteSynchronously选项来尝试同步执行该后续操作。如果后续操作耗时非常短暂,使用以上方式是非常有用的,因为放置在主线程中运行比放置在线程池中运行要快。可以实现这一点是因为第二个任务恰好在那刻完成。如果注释掉4秒的Thread.Sleep方法,将会看到该代码被放置到线程池中,这是因为还未从之前的任务中得到结果。
最后我们为之前的后续操作也定义了一个后续操作,但这里使用了一个稍微不同的方式,即使用了新的GetAwaiter和OnCompleted方法,这些方法是C#5.0语言中异步机制中的方法。
主逻辑的最后部分与父子线程有关,我们创建了一个新任务,当运行该任务时,通过提供一个TaskCreationOptions.AttachedToParent选项来运行一个所谓的子任务。子任务必须在父任务运行时创建,并正确的附加给父任务。
这意味着只有所有子任务结束工作,父任务才会完成。通过提供一个TaskContinuationOptions选项也可以给在子任务上运行后续操作。该后续操作也会影响父任务,并且直到最后一个子任务结束它才会运行完成。