Postupy: Zastavení nebo zrušení volaní z Parallel.For smyčky
Následující příklad ukazuje jak Break (nebo Exit v Visual Basic) ze smyčky For a také jak ukončit smyčku. V této souvislosti "break" znamená dokončení všech iterací na všech vláknech, které jsou před aktuální iterací v aktuálním vlákně a ukončení smyčky. " Stop" znamená pohodlný co nejdříve zastavit všechny iterací.
Příklad
Tento příklad ukazuje For smyčky; však ukončit nebo přerušit z ForEach smyčky v stejným způsobem. V ForEach smyčky, iterace indexu je generován interně pro každý prvek v každém oddílu.
' 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;
}
}
}
V ParallelFor() nebo [Overload:System.Threading.Tasks.Parallel.Parallel.ForEach`1] smyčkách, nemůžete použít stejné Break nebo Exit výrok, jaké jsou používány v sekvenčních smyčkách, protože tyto jazykové konstrukce jsou platné pro smyčky a paralelní "smyčka" je ve skutečnosti metoda, nikoli smyčka. Místo toho použijte buď Stop nebo Break metody. Některé přetížení Parallel.For přijmout Action<int, ParallelLoopState> (Action(Of Integer, ParallelLoopState) v jazyce Visual Basic) jako vstupní parametr. Objekt ParallelLoopState je vytvořen na pozadí runtime modulem a ve lambda výrazu mu můžete přiřadit libovolný název.
V následujícím příkladu metoda vyžaduje pouze 100 hodnot ze zdrojové sekvence a nezáleží na tom, které prvky byly načteny. V tomto případě je použita Stop metoda, protože zdělí všem iteracím smyčky, (i těm které začaly před aktuální iterací v jiných vláknech) aby se zastavily ihned jak to bude možné.
V druhé metodě načítáme ze zdrojové sekvence všechny elementy až k zadanému indexu. V tomto případě je zavolána metoda Break, protože když dosáhneme indexu v jednom vláknu, je možné že předchozí prvky v sekvenci ještě nebyly zpracovány. Metoda Break způsobí ukončení práce jiných vláken na pozdějších segmentech (pokud se nějakými zabývají) a dokončení zpracování všech předchozí prvků před ukončením smyčky.
Je důležité porozumět, že po tom co je zavolána buď Stop nebo Break metoda, jiná vlákna ve smyčce mohou nadále běžet po jistou dobu, kterou vývojář není schopen ovlivnit. Můžete použít vlastnost ParallelLoopState.IsStopped, k zkontrolování zda byla smyčka zastavena jiným vláknem. V následujícím příkladu, pokud je příznak IsStopped nastaven na TRUE, pak žádná další data nebudou zapsána do kolekce.
Probíhá kompilace kódu
- Zkopírujte a vložte ukázkový kód do projekt Visual Studio 2010.
Viz také
Odkaz
Koncepty
Datový paralelismus (Task Parallel Library)