【问题标题】:How to terminate Parallel.ForEach threads immediately?如何立即终止 Parallel.ForEach 线程?
【发布时间】:2016-01-22 13:31:04
【问题描述】:

我正在调用Parallel.Foreach() 中的一些代码。代码有Thread.Sleep(60000),所以如果我也取消令牌,那么它会在取消 Parallel.ForEach 循环之前等待 60 秒。 Thread.Sleep() 放在此代码中以进行解释。实际代码有一些等待其他资源的代码。 我想在调用cts.Cancel(); 时取消所有活动。

我也尝试了 LoopState,但在我的情况下它不起作用。

 using System;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;

    class Program
    {
        static void Main()
        {
            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, po, (num) =>
                {
                    double d = Math.Sqrt(num);
                    Console.WriteLine("{0} on {1}", d, Thread.CurrentThread.ManagedThreadId);
                    Thread.Sleep(60000); //Thread Sleep for 1 minute
                    po.CancellationToken.ThrowIfCancellationRequested();
                });
            }
            catch (OperationCanceledException e)
            {
                Console.WriteLine(e.Message);
            }
            finally
            {
                cts.Dispose();
            }

            Console.ReadKey();
        }
    }

【问题讨论】:

  • 如果有人告诉你使用Thread.Abort(),把他们赶走。
  • 你基本上不能这样做,因为没有(理智的)方法来中断一些不参与合作取消的代码。通常你会让线程继续,但停止等待它(并忽略它的结果),但使用Parallel.ForEach 做到这一点并不容易
  • "如果 main() 的所有代码都在一个线程下运行..." 但事实并非如此。你刚刚打电话给Parallel.ForEach()。无论如何,read this。正如 Eric Lippert 所说:Thread.Abort 充其量是糟糕设计的表现,可能不可靠,而且极其危险。应该不惜一切代价避免它
  • 无论如何,如果您有一些代码正在等待其他资源,您应该更改它,以便在等待时允许合作取消。
  • @RomilKumarJain - 你在用什么IndexOf 需要这么长时间?也许你的那部分代码需要一些优化?

标签: c# .net multithreading parallel-processing


【解决方案1】:

如果我理解正确的话,您并不是真的需要立即中断线程,而是您只是希望能够在等待时中断Sleep() 方法。 p>

有很多选项,但恕我直言,最简单的一种是使用 CancellationToken.WaitHandle 属性值,然后等待它而不是休眠:

po.CancellationToken.WaitHandle.WaitOne(60000);

如果令牌发出信号,Wait() 方法将在指定的超时之前返回(本例中为一分钟)。

通常您会检查返回值,这样您就可以区分发出信号的句柄和等待超时之间的区别,但在您的情况下,您会立即调用 po.CancellationToken.ThrowIfCancellationRequested();,所以对我来说忽略从Wait() 方法返回值,并让下一个程序语句负责实际中断该方法。

【讨论】:

  • 使用 WaitHandle.WaitOne() 代替 Thread.Sleep() 很好。但我必须检查为什么 IndexOf() 需要这么多时间。我有一些大数据,比如 100KB 字符串。
  • 您提供的代码示例未使用IndexOf(),因此这显然超出了您提出的问题的范围。如果您有一些其他代码,并且您希望能够在它调用IndexOf() 时中断它,那么您将需要编写自己的版本,您可以将CancellationToken 传递给它,它可以使用 while它正在处理以允许自己被中断。
  • 有些时间 IndexOf() 以几秒的时间返回结果,有些时间花费了 30 多秒。我使用了 IndexOf() 的所有组合。
  • 由于您的上述问题不涉及IndexOf(),因此与IndexOf() 讨论问题将超出本问题的范围。如果您在使用该方法的时间过长时遇到问题,请发布一个新问题,并提供一个很好的 minimal reproducible example 以可靠地重现问题。
  • 我不是在寻找与 IndexOf() 相关的解决方案。我正在寻找发布问题的答案,仅用于从 Parallel.ForEach() 终止所有生成线程。
猜你喜欢
  • 1970-01-01
  • 2022-11-21
  • 1970-01-01
  • 1970-01-01
  • 2019-05-03
  • 1970-01-01
  • 1970-01-01
  • 2017-07-30
  • 1970-01-01
相关资源
最近更新 更多