【问题标题】:Can I cancel only one thread when iterating over parallel.foreach?迭代parallel.foreach时我可以只取消一个线程吗?
【发布时间】:2016-12-11 10:48:14
【问题描述】:

当我使用parallel.foreach时,有没有办法取消一个特定的线程?

我知道我可以使用parallelOptions() 取消所有带有cancelToken.token 的线程,但是如何取消一个特定线程

我知道如果我要创建线程列表而不是 parallel.foreach,选择要取消的线程没有问题,但我希望我的程序以并行顺序运行,而不仅仅是异步(因为我想使用我所有的 CPU,而不仅仅是对 CPU 资源进行切片)。

【问题讨论】:

  • 你能解释一下你真正想要完成什么吗?你想停止一个线程,还是循环的迭代?如果它真的是一个线程,为什么? Parallel.ForEach 主要为你管理线程,你不应该做这样的事情。

标签: .net multithreading parallel-processing parallel.foreach


【解决方案1】:

编辑:好的,所以我的第一个想法很糟糕,但这有效:

List<string> Items = new List<string>()
{
    "First",
    "Second",
    "Third",
    "Fourth"
};

Parallel.ForEach(Items, (s, t) =>
{
    if (s == "Second")
        return;
    Console.WriteLine(s);
});

我想这会教我在不等待 Visual Studio 的情况下触发答案,吸取的教训:P

【讨论】:

  • 不,您不能在 Parallel.ForEeach 中使用 continue。相当于只是从 body 函数调用 return;return local;,具体取决于您使用的是 Action overload 还是 Func overload
  • 谢谢,当我启动 VS 并记得 Parallel.ForEach 的签名中有一个委托时,我就得到了它。抱歉误导了。
【解决方案2】:

正如William Xifaras 已经提到的,如果您使用Parallel.ForeachParallel.For,那么ThreadPool 将用于执行您的代码。

您为什么不使用Task&lt;T&gt; 编写一些类似的功能,但要考虑这样的取消。

        Action<CancellationToken> work = (token) =>
        {
            Console.WriteLine($"Work started on Thread: {Thread.CurrentThread.ManagedThreadId}");
            foreach (var i in Enumerable.Range(0, 10))
            {
                if (token.IsCancellationRequested)
                {
                    Console.WriteLine($"Work cancelled on Thread: {Thread.CurrentThread.ManagedThreadId}");
                    return;
                }
                Thread.Sleep(1000);
            }
            Console.WriteLine($"Work complete on Thread: {Thread.CurrentThread.ManagedThreadId}");
        };

        var tasks = new List<Tuple<Task, CancellationTokenSource>>();

        foreach (var i in Enumerable.Range(0, 4))
        {
            var cancellation = new CancellationTokenSource();
            var task = Task.Run(() => work(cancellation.Token), cancellation.Token);
            tasks.Add(new Tuple<Task, CancellationTokenSource>(task, cancellation));
        }

        tasks.First().Item2.Cancel();
        Task.WaitAll(tasks.Select(m => m.Item1).ToArray());

这将产生类似的输出:

Work started on Thread: 3
Work started on Thread: 6
Work started on Thread: 4
Work started on Thread: 5
Work cancelled on Thread: 3
Work complete on Thread: 6
Work complete on Thread: 5
Work complete on Thread: 4

这是你试图达到的目标吗?

【讨论】:

    【解决方案3】:

    为了清楚起见,Parallel 类使用ThreadPool 来排队和执行工作。

    为了回答您的问题,我认为没有办法可以取消特定的“线程”本身,但是您可以在不使用取消令牌的情况下从 Parallel.For 中断。

    请参阅 MSDN 上的以下内容:如何:Stop or Break from a Parallel.For Loop

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-04
      • 1970-01-01
      • 1970-01-01
      • 2018-03-06
      • 2014-12-12
      • 2021-09-21
      • 1970-01-01
      相关资源
      最近更新 更多