Como: Parar ou desvinculá-lo um Loop de Parallel
A exemplo a seguir mostra como quebra (ou Sair em Visual Basic) fora de um For loop e também como interromper um loop. Nesse contexto, "quebrar" significa concluir todas as iterações de todos os threads que estão antes para a iteração atual no thread atual e sair do loop. " Stop" significa parar todas as iterações assim conveniente.
Exemplo
Este exemplo demonstra uma For loop; No entanto, você pode parar ou quebrar a partir de um ForEach loop na mesma maneira. Em um ForEach um índice de iteração de loop é gerado internamente para cada elemento em cada partição.
' How to: Stop or Break from a Parallel.For Loop
Imports System.Collections.Concurrent
Imports System.Threading
Imports System.Threading.Tasks
Module ParallelForStop
Sub Main()
StopLoop()
BreakAtThreshold()
Console.WriteLine("Press any key to exit.")
Console.ReadKey()
End Sub
Sub StopLoop()
Console.WriteLine("Stop loop...")
Dim source As Double() = MakeDemoSource(1000, 1)
Dim results As New ConcurrentStack(Of Double)()
' i is the iteration variable. loopState is a
' compiler-generated ParallelLoopState
Parallel.For(0, source.Length, Sub(i, loopState)
' Take the first 100 values that are retrieved
' from anywhere in the source.
If i < 100 Then
' Accessing shared object on each iteration
' is not efficient. See remarks.
Dim d As Double = Compute(source(i))
results.Push(d)
Else
loopState.[Stop]()
Exit Sub
End If
' Close lambda expression.
End Sub)
' Close Parallel.For
Console.WriteLine("Results contains {0} elements", results.Count())
End Sub
Sub BreakAtThreshold()
Dim source As Double() = MakeDemoSource(10000, 1.0002)
Dim results As New ConcurrentStack(Of Double)()
' Store all values below a specified threshold.
Parallel.For(0, source.Length, Function(i, loopState)
Dim d As Double = Compute(source(i))
results.Push(d)
If d > 0.2 Then
' Might be called more than once!
loopState.Break()
Console.WriteLine("Break called at iteration {0}. d = {1} ", i, d)
Thread.Sleep(1000)
End If
Return d
End Function)
Console.WriteLine("results contains {0} elements", results.Count())
End Sub
Function Compute(ByVal d As Double) As Double
'Make the processor work just a little bit.
Return Math.Sqrt(d)
End Function
' Create a contrived array of monotonically increasing
' values for demonstration purposes.
Function MakeDemoSource(ByVal size As Integer, ByVal valToFind As Double) As Double()
Dim result As Double() = New Double(size - 1) {}
Dim initialval As Double = 0.01
For i As Integer = 0 To size - 1
initialval *= valToFind
result(i) = initialval
Next
Return result
End Function
End Module
namespace StopOrBreak
{
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
class Test
{
static void Main()
{
StopLoop();
BreakAtThreshold();
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
private static void StopLoop()
{
Console.WriteLine("Stop loop...");
double[] source = MakeDemoSource(1000, 1);
ConcurrentStack<double> results = new ConcurrentStack<double>();
// i is the iteration variable. loopState is a
// compiler-generated ParallelLoopState
Parallel.For(0, source.Length, (i, loopState) =>
{
// Take the first 100 values that are retrieved
// from anywhere in the source.
if (i < 100)
{
// Accessing shared object on each iteration
// is not efficient. See remarks.
double d = Compute(source[i]);
results.Push(d);
}
else
{
loopState.Stop();
return;
}
} // Close lambda expression.
); // Close Parallel.For
Console.WriteLine("Results contains {0} elements", results.Count());
}
static void BreakAtThreshold()
{
double[] source = MakeDemoSource(10000, 1.0002);
ConcurrentStack<double> results = new ConcurrentStack<double>();
// Store all values below a specified threshold.
Parallel.For(0, source.Length, (i, loopState) =>
{
double d = Compute(source[i]);
results.Push(d);
if (d > .2)
{
// Might be called more than once!
loopState.Break();
Console.WriteLine("Break called at iteration {0}. d = {1} ", i, d);
Thread.Sleep(1000);
}
});
Console.WriteLine("results contains {0} elements", results.Count());
}
static double Compute(double d)
{
//Make the processor work just a little bit.
return Math.Sqrt(d);
}
// Create a contrived array of monotonically increasing
// values for demonstration purposes.
static double[] MakeDemoSource(int size, double valToFind)
{
double[] result = new double[size];
double initialval = .01;
for (int i = 0; i < size; i++)
{
initialval *= valToFind;
result[i] = initialval;
}
return result;
}
}
}
Em um ParallelFor() ou [Overload:System.Threading.Tasks.Parallel.Parallel.ForEach`1] loop, não é possível usar o mesmo quebra ou Sair instrução que é usada em um loop seqüencial, pois essas construções de linguagem são válidas para loops e "loop" paralelo é realmente um método, e não um loop. Em vez disso, você usar o Stop ou Break métodos. Algumas das sobrecargas de Parallel.For aceitar uma Action<int, ParallelLoopState> (Action(Of Integer, ParallelLoopState) em Visual Basic) como um parâmetro de entrada. O ParallelLoopState objeto é criado nos bastidores pelo tempo de execução, e você pode atribuir qualquer nome que desejar na expressão lambda.
No exemplo a seguir, o método requer apenas 100 valores da seqüência de origem e não importa quais elementos foram recuperados. Nesse caso o Stop método é usado porque informa todas as iterações do loop, incluindo aqueles começou antes para a iteração atual em outros threads, parar, assim é conveniente.
No segundo método, estamos recuperando todos os elementos para um índice especificado na seqüência de origem. Nesse caso, Break é chamado, porque quando podemos alcançar o índice em um segmento, é possível que elementos anteriores na origem ainda não foram processados. Quebra fará com que outros segmentos para abandonar o trabalho em seqments mais recente (se eles estão envolvidos em qualquer) e concluir o processamento de todos os elementos anteriores antes de sair do loop.
É importante entender que, após um Stop ou Break é chamado, outros threads em um loop podem continuar em execução durante um determinado período de tempo, o que não está no controle do desenvolvedor de aplicativo. Você pode usar o ParallelLoopState.IsStopped propriedade para verificar se o loop foi interrompido em outro segmento. No exemplo a seguir, se IsStopped for true, então nenhuma dados são gravados para a coleção.
Compilando o código
- Copie e cole o exemplo de código em um projeto de 2010 de Visual Studio.
Consulte também
Referência
Conceitos
Paralelismo de dados (biblioteca paralela de tarefas)