gpt4 book ai didi

c# - CancellationTokenSource 无法与 Parallel.ForEach 一起正常工作

转载 作者:行者123 更新时间:2023-11-30 16:46:26 27 4
gpt4 key购买 nike

我有以下代码:

 CancellationTokenSource ts = new CancellationTokenSource(10000);
ParallelOptions po = new ParallelOptions();
po.CancellationToken = ts.Token;

List<int> lItems = new List<int>();

for (int i = 0; i < 20; i++)
lItems.Add(i);

System.Collections.Concurrent.ConcurrentBag<int> lBgs = new System.Collections.Concurrent.ConcurrentBag<int>();

Stopwatch sp = Stopwatch.StartNew();
try
{
Parallel.ForEach(lItems, po, i =>
{
Task.Delay(i * 1000).Wait();
lBgs.Add(i);
});
}
catch (Exception ex)
{
}

Console.WriteLine("Elapsed time: {0:N2} seg Total items: {1}", sp.ElapsedMilliseconds / 1000.0, lBgs.Count);

我的问题是,如果 CancellationTokenSource 设置为在 10 秒内完成,为什么需要超过 20 秒来取消操作(并行)

问候

最佳答案

没有好的Minimal, Complete, and Verifiable code example ,不可能完全理解你的场景。但是根据您发布的代码,您似乎希望您的 CancellationToken 影响 Parallel.ForEach() 的每个单独迭代的执行。

然而,这不是它的工作原理。 Parallel.ForEach() 方法同时安排各个操作,但一旦这些操作开始,它们就不受 Parallel.ForEach() 方法的控制。如果你想让他们提前终止,你必须自己做。例如:

 Parallel.ForEach(lItems, po, i =>
{
Task.Delay(i * 1000, ts.Token).Wait();
lBgs.Add(i);
});

在您的代码中,所有 20 个操作几乎立即开始(有一个短暂的延迟,因为线程池为所有操作创建了足够的线程,如有必要),然后您取消 token 。也就是说,在您取消 token 时,Parallel.ForEach() 方法不再有办法避免启动操作;他们已经开始了!

既然你的个人行为不会做任何事情来打断他们自己,那么剩下的就是让他们全部完成。启动时间(包括等待线程池创建足够的工作线程),加上最长的总延迟(即开始一个 Action 的延迟加上该 Action 的延迟),决定了操作所花费的总时间,以及你的取消 token 没有效果。由于您最长的操作是 20 秒,因此 Parallel.ForEach() 操作的总延迟将始终至少为 20 秒。

通过进行我上面显示的更改,每个单独操作的延迟任务将在 token 到期时被您的 token 取消,从而导致任务取消异常。这也会导致操作本身提前终止。

请注意,将取消 token 分配给 ParallelOptions.CancellationToken 属性仍然有值(value)。即使取消发生得太晚,无法阻止 Parallel.ForEach() 启动所有操作,通过在选项中提供标记,它可以识别出每个操作抛出的异常是由选项中使用的相同取消标记。这样一来,它就可以仅抛出一个 OperationCanceledException,而不是将所有操作异常包装在一个 AggregateException 中。

关于c# - CancellationTokenSource 无法与 Parallel.ForEach 一起正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40389334/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com