【问题标题】:Cancel all running thread of C# Parallel.Foreach immediately立即取消 C# Parallel.Foreach 的所有正在运行的线程
【发布时间】:2013-12-24 05:02:18
【问题描述】:

我正在使用Multithreading 来解决我的问题。我一直在后台工作人员DoWork 事件中使用Parallel.Foreach,其中长时间运行的作业一直在执行。但是,当我不得不取消工作时,问题就出现了。它不会立即取消线程。

BackgroundWorker DoWork 事件:

private void File_DoWork(object sender, DoWorkEventArgs e)
{
    var cts = new CancellationTokenSource();
    btnCancel.Click += (cancelSender, cancelEvent) =>
                {
                     bgwFile.CancelAsync();

                     if (bgwFile.CancellationPending)
                     {
                         cts.Cancel();
                         e.Cancel = true;
                     }
                };
    object sync = new object();
    List<Response> responses = null;

    var parallelOperation = new ParallelOptions
    {
          MaxDegreeOfParallelism = 3,
          CancellationToken = cts.Token
    };

    Parallel.ForEach(listRequest, parallelOperation, request =>
    {
        lock (sync)
        {
             responses = GetQueryResponse(request); // Long running process      
             parallelOperation.CancellationToken.ThrowIfCancellationRequested();
        }
    });
    e.Result = responses ;
}

在这里,问题是我必须取消长时间运行的作业。假设,有三个请求已经通过parallel.foreach循环,具有MaxDegreeOfParallelism = 3,那么它适用于GetQueryResponse(request)方法,这是一个很长的工作,如果我使用CancellationTokenSource取消线程,那么它不会立即取消进程.只有在执行了 3 个请求线程后才会取消。

我希望它立即取消它。有什么办法可以立即取消Parallel.Foreach产生的所有正在运行的线程,并转到backgroundworker的RunWorkerCompleted事件?

【问题讨论】:

  • 至少你应该确保你的代码 sn-ps 在发布之前编译,这不可能是因为responses 在它被声明的范围之外被访问。跨度>
  • 谢谢 kirill..事实上,上面的 sn-p 是我实际的示例代码...感谢您指出...:)
  • 嗯,使用您使用的锁,您没有并行执行任何操作。据我所知...
  • @FelicePollano :我在并行内部也有其他操作。但主要问题发生在responses = GetQueryResponse(request);

标签: c# multithreading c#-4.0 task-parallel-library backgroundworker


【解决方案1】:

您可以使用CancellationToken.Register Method (Action)注册一个委托,当这个CancellationToken 被取消时将被调用。

一旦请求取消,它将被解雇。当然,你必须编写导致当前GetQueryResponse执行立即停止的逻辑。

【讨论】:

  • 对了,GetQueryResponse 是长时间运行的 IO 操作(比如在网络中搜索文件),有什么办法可以在运行时强行取消该操作?
  • 这取决于操作本身。没有什么可以让你明确地kill TPL 任务,就像你对Thread 类实例所做的那样。检查这个答案:How do I abort/cancel TPL Tasks?.
【解决方案2】:

检查 TPL 的 CancellationTokens。here 将 CancellationToken 传递给 Parallel.Foreach() 可以使其工作。当您想停止所有任务时,只需使用:

cts.Cancel()

在你的任务方法的地方

cts.Token.ThrowIfCancellationRequested(); 当您想检查是否需要停止任务,因为另一个任务取消了进程。

【讨论】:

  • 我正在使用 CancellationTokens 但它不能帮助我立即取消所有线程..
【解决方案3】:

您可以将线程的 IsBackground 属性设置为 true。当您的应用完成时,这将终止所有线程。

您可以使用一个计时器(或一个线程)来唤醒和检查数据。那应该对资源更友好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-02
    • 2017-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-10
    相关资源
    最近更新 更多