立即取消C# Parallel.Foreach的所有正在运行的线程

3

我正在使用多线程方法解决我的问题。我一直在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 ;
}

在这里,问题是当我需要取消长时间运行的作业时。假设有三个请求通过并行.foreach循环并具有MaxDegreeOfParallelism = 3,然后它进入长时间执行的GetQueryResponse(request)方法,如果我使用CancellationTokenSource取消线程,则不会立即取消进程。它只会在执行3个请求线程之后才取消。
我希望能够立即取消它。是否有任何方法可以立即取消由Parallel.Foreach产生的所有正在运行的线程并转到backgroundworker的RunWorkerCompleted事件?

1
至少在发布代码片段之前,您应确保其编译通过,但由于“responses”在声明范围之外被访问,这显然不可能是这种情况。 - Kirill Shlenskiy
谢谢Kirill。实际上,上面的片段是我的实际代码的示例...感谢您指出... :) - Akash KC
1
嗯,根据你使用的锁,我看不出你在做任何并行处理。 - Felice Pollano
@FelicePollano: 我在并行处理中还有其他操作。但主要问题出现在responses = GetQueryResponse(request);这里。 - Akash KC
3个回答

3

您可以使用CancellationToken.Register 方法(Action) 来注册一个委托,当此CancellationToken被取消时将会被调用。

它会在请求取消时立即触发。当然,您需要编写逻辑来使当前的GetQueryResponse执行立即停止。


顺便说一下,GetQueryResponse是一个长时间运行的IO操作(例如在网络中搜索文件)。在运行时有没有强制取消操作的方法? - Akash KC
这取决于操作本身。没有任何东西可以像您使用Thread类实例一样显式地kill TPL任务。请查看此答案:如何中止/取消TPL任务? - MarcinJuraszek

0

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

cts.Cancel()

在你的任务方法中加入以下代码:

cts.Token.ThrowIfCancellationRequested();

当你想要检查任务是否需要停止,因为另一个任务取消了该过程时使用。

我正在使用CancellationTokens,但它不能立即取消所有线程。 - Akash KC

-2

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

您可以使用一个定时器(或一个线程)来唤醒并检查数据。这样更加节省资源。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接