當前位置: 妍妍網 > 碼農

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.



    透過使用相關型別並強制轉換它,您可以從任務中獲取數據。

    如果你喜歡我的文章,請給我一個贊!謝謝