当前位置: 欣欣网 > 码农

C# 中的并行任务库 (TPL)

2024-04-03码农


概述: TPL 在 C# 中代表「任务并行库」。它是 .NET Framework 提供的一组类和 API,用于简化编写_并行和异步代码的过程。TPL 使开发人员能够更轻松地利用多核处理器并编写可同时执行任务的代码,从而提高其应用程序的性能。TPL 中的概念是「Task」类,它表示可以与其他任务同时运行的异步操作。开发人员可以使用任务来并行化操作、管理异步操作以及编写复杂的异步工作流。TPL 提供了用于管理任务的各种功能和构造,例如并行循环、用于异步编程的「async」和「await」关键字,以及用于协调多个任务的方法,例如「Task.WhenAll」和「Task.WhenAny」。_异步编程与并行编

TPL 在 C# 中代表「任务并行库」。它是 .NET Framework 提供的一组类和 API,用于简化编写_ 并行和异步代码 的过程。TPL 使开发人员能够更轻松地利用多核处理器并编写可 同时执行任务 的代码,从而提高其应用程序的 性能 。TPL 中的概念是 「Task」 类,它表示可以 与其他任务同时 运行的 异步操作 。开发人员可以使用任务来 并行化操作、管理异步操作以及编写复杂的异步工作流 。TPL 提供了用于管理任务的各种功能和构造,例如 并行循环 、用于异步编程的 「async」 「await」 关键字,以及用于协调多个任务的方法,例如 「Task.WhenAll」 「Task.WhenAny」。 _

异步编程与并行编程

异步编程

  1. 允许_ 单个 线程有效地处理多个任务而不会阻塞:主要关注点是响应能力。并且还可以释放线程来执行其他工作,同时等待 缓慢 不可预测的 _操作完成

  2. 使用 和 关键字实现。asyncawait

  3. 例如:读取文件、发出网络请求或等待用户输入。

并行编程

  1. 将任务划分为更小的子任务,并使用_ 多个 线程或进程 同时 _执行这些子任务,以提高性能。

  2. 可以使用任务并行库 (TPL) 实现。

  3. 例如:CPU 密集型任务,可利用多个 CPU 内核更快地执行计算

分步指南

  1. 命名空间

usingSystem;
usingSystem.Threading.Tasks;

2. 使用返回值创建任务

//create a new task called task1
Task task1 = Task.Run(() => {
returntrue;
});
//use value of task1
bool result = task1.Result;

3.等待任务完成

// This blocks wait until task1 is completed
task1.Wait();
// This blocks wait until all tasks of the taskArray are completed
Task.WaitAll(taskArray);
// This blocks wait until any task of the taskArray is completed
Task.WaitAny(taskArray);

4 . 任务延续

ContinueWith用于指定在_ 上一个任务完成后 应运行的延续任务。它允许您创建一系列任务,其中一个任务的完成会触发另一个任务的执行。默认情况下,不等待上一个任务完成。相反, 它会在上一个任务完成后立即开始运行 _,而不管上一个任务是成功还是遇到异常。这种行为通常被称为「**即发即弃」。**ContinueWith"

//create a task called task1 and return integer value
Task<int> task1 = Task.Run(() => 42);
//create task2 with a continuation on task1
Task<string> task2 = task1.ContinueWith(previousTask => {
//get the task1 returning data
int result = previousTask.Result;
return$"previous task return value is {result}";
});

解释:

当您在 continue on 的情况下创建时,继续任务 () 将等到完成后才开始执行。因此,在完成执行之前不会开始。task4task3task4task3task4task3

  • task3 是使用 Task.Run(() => 42) 创建并启动的。

  • task4 是使用 ContinueWith 方法创建的,作为 task3 的延续。

  • 由于 task3 在创建 task4 之前就已启动,因此 task4 将等待 task3 完成,然后再开始执行。

  • 一旦 task3 完成(在本例中,当它返回值 42 时), task4 将执行其代码。

  • 5. TaskFactory.Start新建

    在一个操作中创建并启动任务。

    Task.Factory.StartNew(() => DoComputation(1.0));
    privatestaticDoubleDoComputation(Double start)
    {
    Double sum = 0;
    for (varvalue = start; value <= start + 10; value += .1)
    sum += value;
    return sum;
    }

    6. 分离的子任务

    父任务和子任务之间没有同步。父任务不会等待分离的子任务完成。

    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.");
    // The example displays the following output:
    // Outer task beginning.
    // Outer task completed.
    // Detached task completed.

    7. 附加的子任务

    通过指定选项。AttachToParent

    publicstaticvoidMain()
    {
    var parent = Task.Factory.StartNew(() => {
    Console.WriteLine("Parent task beginning.");
    for (int ctr = 0; ctr < 10; ctr++) {
    int taskNo = ctr;
    Task.Factory.StartNew((x) => {
    Thread.SpinWait(5000000);
    Console.WriteLine("Attached child #{0} completed.",
    x);
    },
    taskNo, TaskCreationOptions.AttachedToParent);
    }
    });
    parent.Wait();
    Console.WriteLine("Parent task completed.");
    }
    // The example displays output like the following:
    // Parent task beginning.
    // Attached child #9 completed.
    // Attached child #0 completed.
    // Attached child #8 completed.
    // Attached child #1 completed.
    // Attached child #7 completed.
    // Attached child #2 completed.
    // Attached child #6 completed.
    // Attached child #3 completed.
    // Attached child #5 completed.
    // Attached child #4 completed.
    // Parent task completed.

    8 . 任务示例

    使用方法时会传播异常,并通过添加语句来处理异常。异常类型为 。Task.Wait()Task.Wait()try & catchAggregateException

    publicstaticpartial classProgram
    {
    publicstaticvoidHandleThree()
    {
    var task = Task.Run(
    () => thrownewCustomException("This exception is expected!"));
    try
    {
    task.Wait();
    }
    catch (AggregateException ae)
    {
    foreach (var ex in ae.InnerExceptions)
    {
    // Handle the custom exception.
    if (ex isCustomException)
    {
    Console.WriteLine(ex.Message);
    }
    // Rethrow any other exception.
    else
    {
    throw ex;
    }
    }
    }
    }
    }
    // The example displays the following output:
    // This exception is expected!

    9. 附加的子任务示例

    通过访问内部异常。

    publicstaticpartial classProgram
    {
    publicstaticvoidFlattenTwo()
    {
    var task = Task.Factory.StartNew(() =>
    {
    var child = Task.Factory.StartNew(() =>
    {
    var grandChild = Task.Factory.StartNew(() =>
    {
    // This exception is nested inside three AggregateExceptions.
    thrownewCustomException("Attached child2 faulted.");
    }, TaskCreationOptions.AttachedToParent);
    // This exception is nested inside two AggregateExceptions.
    thrownewCustomException("Attached child1 faulted.");
    }, TaskCreationOptions.AttachedToParent);
    });
    try
    {
    task.Wait();
    }
    catch (AggregateException ae)
    {
    foreach (var ex in ae.Flatten().InnerExceptions)
    {
    if (ex isCustomException)
    {
    Console.WriteLine(ex.Message);
    }
    else
    {
    throw;
    }
    }
    }
    }
    }
    // The example displays the following output:
    // Attached child1 faulted.
    // Attached child2 faulted.

    10. 异步状态

    publicstaticvoidMain()
    {
    //Create array of tasks
    Task[] taskArray = newTask[10];
    //Assign, create and run tasks into task array
    for (int i = 0; i < taskArray.Length; i++)
    {
    taskArray[i] = Task.Factory.StartNew((Object obj) =>
    {
    CustomData data = obj asCustomData;
    if (data == null) return;
    data.ThreadNum = Thread.CurrentThread.ManagedThreadId;
    },
    newCustomData() { Name = i, CreationTime = DateTime.Now.Ticks });
    }
    //This waits until all tasks of the taskArray are completed
    Task.WaitAll(taskArray);

    foreach (var task in taskArray)
    {
    var data = task.AsyncState asCustomData;
    if (data != null)
    Console.WriteLine("Task #{0} created at {1}, ran on thread #{2}.",
    data.Name, data.CreationTime, data.ThreadNum);
    }
    }
    // The example displays output like the following:
    // Task #0 created at 635116412924597583, ran on thread #3.
    // Task #1 created at 635116412924607584, ran on thread #4.
    // Task #2 created at 635116412924607584, ran on thread #4.
    // Task #3 created at 635116412924607584, ran on thread #4.
    // Task #4 created at 635116412924607584, ran on thread #3.
    // Task #5 created at 635116412924607584, ran on thread #3.
    // Task #6 created at 635116412924607584, ran on thread #4.
    // Task #7 created at 635116412924607584, ran on thread #4.
    // Task #8 created at 635116412924607584, ran on thread #3.
    // Task #9 created at 635116412924607584, ran on thread #4.



    通过使用相关类型并强制转换它,您可以从任务中获取数据。

    如果你喜欢我的文章,请给我一个赞!谢谢