簡體   English   中英

在 C# 中取消 Parallel.ForEach 中的單個任務或特定任務

[英]Cancelling a single Task or Particular Tasks in Parallel.ForEach in c#

我有一個要求,我們使用 Parallel.ForEach 運行一些任務。 用戶可以決定從提供給 Parallel.ForEach 的 TaskList 中取消任何任務或單個任務。 我嘗試過使用 CancellationToken 但它會為 TaskList 中的所有任務觸發。 我也試過 ParallelLoopState 但即使這樣也不能做我想要的。

我使用以下代碼處理此 POC,但無法使其正常工作。

瓶頸在下面的語句中

Parallel.ForEach(nums, new ParallelOptions() { CancellationToken = new CancellationToken() } , (num) =>

由於我們必須在 Foreach 中傳遞取消令牌,因此我無法為 Foreach 循環中的每個項目傳遞單獨的取消令牌。

我不想采用那種 Task 方法,因為 Task 與 Parallel 涉及開銷。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;

class Program
{
    static void Main(string[] args)
    {
        int[] nums = Enumerable.Range(0, 10000000).ToArray();
        CancellationTokenSource cts = new CancellationTokenSource();

        // Use ParallelOptions instance to store the CancellationToken
        ParallelOptions po = new ParallelOptions();
        po.CancellationToken = cts.Token;
        po.MaxDegreeOfParallelism = System.Environment.ProcessorCount;
        Console.WriteLine("Press any key to start. Press 'c' to cancel.");
        Console.ReadKey();

        // Run a task so that we can cancel from another thread.
        Task.Factory.StartNew(() =>
        {
            if (Console.ReadKey().KeyChar == 'c')
                cts.Cancel();

            Console.WriteLine("press any key to exit");
        });

        try
        {   
            Parallel.ForEach(nums, new ParallelOptions() { CancellationToken = new CancellationToken() } , (num) =>
            {
                double d = Math.Sqrt(num);
                Console.WriteLine("{0} on {1}", d, Thread.CurrentThread.ManagedThreadId);
                po.CancellationToken.ThrowIfCancellationRequested();
            });
        }
        catch (OperationCanceledException e)
        {
            Console.WriteLine(e.Message);
        }
        finally
        {
            cts.Dispose();
        }

        Console.ReadKey();
}

如果我正確理解您的問題,您應該能夠為每個任務(或任務組,無論標准是什么)創建單獨的取消標記。 在執行任務的昂貴部分之前,您可以在適當的令牌上顯式調用ThrowIfCancellationRequested

// Assume the nums.length == tokens.length
int[] nums = Enumerable.Range(0, 10000000).ToArray();
CancellationToken[] tokens = ...

try
{
    Parallel.ForEach(nums, (num) =>
    {
        tokens[num].ThrowIfCancellationRequested();
        double d = Math.Sqrt(num);
        Console.WriteLine("{0} on {1}", d, Thread.CurrentThread.ManagedThreadId);        
    });
}
catch (AggregateException e)
{
    // One or more tasks was canceled or threw an exception.
    // e.InnerExceptions contains the individual OperationCanceledException
    // or other exceptions that were thrown.
}

請注意檢查任務中的令牌與向Parallel.ForEach提供令牌之間的區別。 取消整個Parallel.ForEach應該避免運行任何尚未啟動的任務並拋出單個 OperationCanceledException。

ParallelOptions po = new ParallelOptions();
po.CancellationToken = cts.Token;
// ...

try
{
    Parallel.ForEach(nums, po, (num) => { ... });
}
catch (OperationCanceledException e)
{
    // The entire operation was cancelled.
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM