如何停止 Parallel.ForEach 循环?

3

我有这段代码来启动一个Parallel ForEach循环:

Parallel.ForEach<ListViewItem>(filesListView.Items.Cast<ListViewItem>(), new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, item => {
    if (CallToStop == true)
        {  
            //Code here to stop the loop!
        }        
    internalProcessStart(item);
});

我有一些代码会检查是否有停止线程的调用,然后我想使用 break; 中断代码,但这在并行处理中不起作用。
我发现有一个相同的问题是由其他人提出的,但他们的代码与我的略有不同,我不确定在哪里放置ParallelLoopState state
谢谢!

您可以在ForEach循环体中进行编辑吗? - Kevin Le
@KevinLe 好的,完成了! - user2924019
4个回答

6

请按照以下方式改写

Parallel.ForEach<ListViewItem>(filesListView.Items.Cast<ListViewItem>(), 
            new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, 
           (item, state) => {
    if (CallToStop == true)
        {  
            state.Break();
        }        
    internalProcessStart(item);
});

希望这可以帮到你。

谢谢,这是我使用的代码,它运行得很好。谢谢。 - user2924019

1

我认为使用这个overload应该可以解决问题:

    Parallel.ForEach<ListViewItem>(filesListView.Items.Cast<ListViewItem>(), new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, (item , state)  => 
    {
        if (/*Stop condition here*/)
        { 
            state.Break(); 
        }        
        internalProcessStart(item);
    });

1

请尝试使用 CancellationToken,就像这个示例(MSDN)中所演示的那样。

可以尝试类似以下代码:

CancellationTokenSource cts = new CancellationTokenSource();

       // Use ParallelOptions instance to store the CancellationToken
        ParallelOptions po = new ParallelOptions();
        po.CancellationToken = cts.Token;
        po.MaxDegreeOfParallelism = Environment.ProcessorCount;

        try
        {
            Parallel.ForEach<ListViewItem>(filesListView.Items.Cast<ListViewItem>(), po, item => {
                // po.CancellationToken.ThrowIfCancellationRequested(); //1
                if (CallToStop == true)
                {  
                    //Code here to stop the loop!
                    cts.Cancel();
                }
                if (po.CancellationToken.IsCancellationRequested == false)
                {        
                    internalProcessStart(item);
                }
            });
        }
        catch (OperationCanceledException e)
        {
            // handle
        }
        finally
        {
            cts.Dispose();
        }

或者您可以直接调用cts.Cancel(),而不是设置CallToStop = true

或者您可以取消注释//1,并让所有未完成的线程抛出OperationCanceledException(仅在由于错误导致CallToStop = true时停止所有并行线程时使用)。

您甚至可以将cts.Token传递到您的internalProcessStart(item,token)中,并处理在内部进程已经运行时取消操作时该怎么做。


1

尝试使用类似以下的代码。从概念上讲,您需要将 loopState 传递给 lambda 函数。

Parallel.ForEach<int>(new List<int>(),
            new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount },
            (val, loopState) =>
            {
                if (val == 9) //enter your stopcondition here
                {
                    loopState.Stop();
                    return;
                }
            });

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