[英]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.