.NET Framework 4
 
其他版本
 
评价此主题
 

 

更新:2011 年 3 月

任务提供两个主要好处:

  • 系统资源的使用效率更高,可伸缩性更好。

    为了补偿这一点,可使用众所周知的工作窃取算法提供负载平衡。

  • 对于线程或工作项,可以使用更多的编程控件。

    任务和围绕它们生成的框架提供了一组丰富的 API,这些 API 支持等待、取消、继续、可靠的异常处理、详细状态、自定义计划等功能。

出于这两个原因,在 .NET Framework 4 中,任务是用于编写多线程、异步和并行代码的首选 API。

Invoke 调用,该调用创建并启动同时运行的两个任务。

注意

在 PLINQ 和 TPL 中的 Lambda 表达式

 
Parallel.Invoke(() => DoSomeWork(), () => DoSomeOtherWork());


注意

TPL 可能会使用各种优化,特别是对于大量的委托。

如何:使用 Parallel.Invoke 来执行并行操作

Task 对象。

TaskStatus 枚举表示。

lambda 表达式可以包含对命名方法的调用,如下面的示例所示。

 
            // Create a task and supply a user delegate by using a lambda expression.
            var taskA = new Task(() => Console.WriteLine("Hello from taskA."));

            // Start the task.
            taskA.Start();

            // Output a message from the joining thread.
            Console.WriteLine("Hello from the calling thread.");


            /* Output:
             * Hello from the joining thread.
             * Hello from taskA. 
             */



如果不必将创建和计划分开,则这是创建和启动任务的首选方法,如下面的示例所示

 
// Create and start the task in one operation.
var taskA = Task.Factory.StartNew(() => Console.WriteLine("Hello from taskA."));

// Output a message from the joining thread.
Console.WriteLine("Hello from the joining thread.");


Result,则该属性将阻止线程,直到值可用为止。

 
Task<double>[] taskArray = new Task<double>[]
   {
       Task<double>.Factory.StartNew(() => DoComputation1()),

       // May be written more conveniently like this:
       Task.Factory.StartNew(() => DoComputation2()),
       Task.Factory.StartNew(() => DoComputation3())                
   };

double[] results = new double[taskArray.Length];
for (int i = 0; i < taskArray.Length; i++)
    results[i] = taskArray[i].Result;


如何:从任务中返回值

通过使用构造函数向任务提供状态对象,可以访问每次迭代的值,如下面的示例所示:

 
       class MyCustomData
       {
        public long CreationTime;
        public int Name;
        public int ThreadNum;
        }

    void TaskDemo2()
    {
        // Create the task object by using an Action(Of Object) to pass in custom data
        // in the Task constructor. This is useful when you need to capture outer variables
        // from within a loop. As an experiement, try modifying this code to 
        // capture i directly in the lambda, and compare results.
        Task[] taskArray = new Task[10];

        for(int i = 0; i < taskArray.Length; i++)
        {
            taskArray[i] = new Task((obj) =>
                {
                                        MyCustomData mydata = (MyCustomData) obj;
                                        mydata.ThreadNum = Thread.CurrentThread.ManagedThreadId;
                                        Console.WriteLine("Hello from Task #{0} created at {1} running on thread #{2}.",
                                                          mydata.Name, mydata.CreationTime, mydata.ThreadNum)
                },
            new MyCustomData () {Name = i, CreationTime = DateTime.Now.Ticks}
            );
            taskArray[i].Start();
        }
    }



另外,在某些情况下,通过构造函数传递数据可以获得少量性能改进。

使用“并行堆栈”窗口

下表列出了各种任务创建选项。

 

元素

说明

None

计划程序将使用其默认试探法来计划任务。

PreferFairness

指定应当计划任务,以使越早创建的任务将更可能越早执行,而越晚创建的任务将更可能越晚执行。

LongRunning

指定该任务表示长时间运行的操作。

AttachedToParent

嵌套任务和子任务

PreferFairness 选项的任务。

 
var task3 = new Task(() => MyLongRunningMethod(),
                    TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness);
task3.Start();


Result 属性中的程序。

 
            Task<byte[]> getData = new Task<byte[]>(() => GetFileData());
            Task<double[]> analyzeData = getData.ContinueWith(x => Analyze(x.Result));
            Task<string> reportData = analyzeData.ContinueWith(y => Summarize(y.Result));

            getData.Start();

            //or...
            Task<string> reportData2 = Task.Factory.StartNew(() => GetFileData())
                                        .ContinueWith((x) => Analyze(x.Result))
                                        .ContinueWith((y) => Summarize(y.Result));

            System.IO.File.WriteAllText(@"C:\reportFolder\report.txt", reportData.Result);





如何:用延续将多个任务链接在一起

下面的示例演示一个任务,该任务创建一个分离的嵌套任务。

 
            var outer = Task.Factory.StartNew(() =>
            {
                Console.WriteLine("Outer task beginning.");

                var child = Task.Factory.StartNew(() =>
                {
                    Thread.SpinWait(5000000);
                    Console.WriteLine("Detached task completed.");
                });

            });

            outer.Wait();
            Console.WriteLine("Outer task completed.");

            /* Output:
                Outer task beginning.
                Outer task completed.
                Detached task completed.

             */



请注意,外部任务不会等待嵌套任务完成。

下面的示例演示一个任务,该任务创建一个子任务:

 
var parent = Task.Factory.StartNew(() =>
{
    Console.WriteLine("Parent task beginning.");

    var child = Task.Factory.StartNew(() =>
    {
        Thread.SpinWait(5000000);
        Console.WriteLine("Attached child completed.");
    }, TaskCreationOptions.AttachedToParent);

});

parent.Wait();
Console.WriteLine("Parent task completed.");

/* Output:
    Parent task beginning.
    Attached task completed.
    Parent task completed.
 */


嵌套任务和子任务

Task.WaitAny 方法的重载使您可以等待任务数组的任一任务或所有任务完成。

通常,会出于以下某个原因等待任务:

  • 主线程依赖于任务计算的最终结果。

  • 您必须处理可能从任务引发的异常。

下面的示例演示不包含异常处理的基本模式。

 
Task[] tasks = new Task[3]
{
    Task.Factory.StartNew(() => MethodA()),
    Task.Factory.StartNew(() => MethodB()),
    Task.Factory.StartNew(() => MethodC())
};

//Block until all tasks complete.
Task.WaitAll(tasks);

// Continue on this thread...


如何:处理由任务引发的异常

CancellationToken 作为输入参数,以便可以通过编程方式或为了响应用户输入来取消等待本身。

Wait 方法也会引发由该任务引发的任何异常。

如何:等待一个或多个任务完成

() 属性,或者通过在 try-catch 块中包括 Wait 方法,来处理异常。

通过访问此属性,可防止未处理的异常触发在对象完成时关闭进程的异常传播行为。

如何:处理由任务引发的异常

CancellationToken

如何:取消任务及其子级

TaskFactory 类提供静态方法,这些方法封装了用于创建和启动任务和延续任务的一些常用模式。

  • ()

  • 延续任务

  • TPL 和传统 .NET 异步编程

TaskCreationOptions 枚举创建的(在这种情况下,任务的选项重写任务工厂的选项)。

TaskCompletionSource<TResult>

TaskScheduler

用于并行编程的数据结构

扩展方法 (Visual Basic)

Task<TResult> 对象。

 

Title

说明

延续任务

描述延续任务的工作方式。

嵌套任务和子任务

描述子任务与嵌套任务之间的差异。

任务取消

Task 类中内置的取消支持。

异常处理(任务并行库)

描述如何处理并行线程中的异常。

如何:使用 Parallel.Invoke 来执行并行操作

Invoke

如何:从任务中返回值

描述如何从任务中返回值。

如何:等待一个或多个任务完成

描述如何等待任务。

如何:取消任务及其子级

描述如何取消任务。

如何:处理由任务引发的异常

描述如何处理由任务引发的异常。

如何:用延续将多个任务链接在一起

描述在一个任务完成时如何执行另一个任务。

如何:使用并行任务遍历二叉树

描述如何使用任务遍历二叉树。

数据并行(任务并行库)

ForEach 来创建循环访问数据的并行循环。

.NET Framework 中的并行编程

.NET 并行编程的顶级节点。

 

日期

修订记录

原因

 

2011 年 3 月

Task<TResult> 类继承的信息。

 

信息补充。

相关文章:

猜你喜欢
相关资源
相似解决方案