Procedura: concatenare più attività con continuazioni
Nella libreria Task Parallel Library, un'attività il cui metodo ContinueWith viene richiamato è detta attività precedente mentre l'attività definita nel metodo ContinueWith è detta continuazione. In questo esempio viene illustrato come utilizzare i metodi ContinueWith e ContinueWith delle classi Task e Task<TResult> per specificare un'attività che viene avviata al termine della relativa attività precedente.
Nell'esempio viene inoltre mostrato come specificare una continuazione che viene eseguita solo se la relativa attività precedente viene annullata.
In questi esempi viene mostrato come continuare da una singola attività. È anche possibile creare una continuazione che viene eseguita dopo il completamento o l'annullamento di alcune o di tutte le attività di un gruppo. Per ulteriori informazioni, vedere TaskContinueWhenAll() e TaskContinueWhenAny().
Esempio
Il metodo DoSimpleContinuation illustra la sintassi di base di ContinueWith. Notare che l'attività precedente viene fornita come parametro di input all'espressione lambda nel metodo ContinueWith. In questo modo è possibile valutare lo stato dell'attività precedente prima che quest'ultima esegua qualsiasi operazione nella continuazione. Utilizzare questo overload semplice di ContinueWith quando non è necessario passare uno stato da un'attività a un'altra.
Il metodo DoSimpleContinuationWithState mostra come utilizzare ContinueWith per passare il risultato dall'attività precedente all'attività di continuazione.
Imports System.IO
Imports System.Threading
Imports System.Threading.Tasks
Module ContinueWith
Sub Main()
DoSimpleContinuation()
Console.WriteLine("Press any key to exit")
Console.ReadKey()
End Sub
Sub DoSimpleContinuation()
Dim path As String = "C:\users\public\TPLTestFolder\"
Try
Dim firstTask = New Task(Sub() CopyDataIntoTempFolder(path))
Dim secondTask = firstTask.ContinueWith(Sub(t) CreateSummaryFile(path))
firstTask.Start()
Catch e As AggregateException
Console.WriteLine(e.Message)
End Try
End Sub
' A toy function to simulate a workload
Sub CopyDataIntoTempFolder(ByVal path__1 As String)
System.IO.Directory.CreateDirectory(path__1)
Dim rand As New Random()
For x As Integer = 0 To 49
Dim bytes As Byte() = New Byte(999) {}
rand.NextBytes(bytes)
Dim filename As String = Path.GetRandomFileName()
Dim filepath As String = Path.Combine(path__1, filename)
System.IO.File.WriteAllBytes(filepath, bytes)
Next
End Sub
Sub CreateSummaryFile(ByVal path__1 As String)
Dim files As String() = System.IO.Directory.GetFiles(path__1)
Parallel.ForEach(files, Sub(file)
Thread.SpinWait(5000)
End Sub)
System.IO.File.WriteAllText(Path.Combine(path__1, "__SummaryFile.txt"), "did my work")
Console.WriteLine("Done with task2")
End Sub
Sub DoSimpleContinuationWithState()
Dim nums As Integer() = {19, 17, 21, 4, 13, 8, _
12, 7, 3, 5}
Dim f0 = New Task(Of Double)(Function() nums.Average())
Dim f1 = f0.ContinueWith(Function(t) GetStandardDeviation(nums, t.Result))
f0.Start()
Console.WriteLine("the standard deviation is {0}", f1)
End Sub
Function GetStandardDeviation(ByVal values As Integer(), ByVal mean As Double) As Double
Dim d As Double = 0.0R
For Each n In values
d += Math.Pow(mean - n, 2)
Next
Return Math.Sqrt(d / (values.Length - 1))
End Function
End Module
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace ContinueWith
{
class Continuations
{
static void Main()
{
SimpleContinuation();
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
static void SimpleContinuation()
{
string path = @"C:\users\public\TPLTestFolder\";
try
{
var firstTask = new Task(() => CopyDataIntoTempFolder(path));
var secondTask = firstTask.ContinueWith((t) => CreateSummaryFile(path));
firstTask.Start();
}
catch (AggregateException e)
{
Console.WriteLine(e.Message);
}
}
// A toy function to simulate a workload
static void CopyDataIntoTempFolder(string path)
{
System.IO.Directory.CreateDirectory(path);
Random rand = new Random();
for (int x = 0; x < 50; x++)
{
byte[] bytes = new byte[1000];
rand.NextBytes(bytes);
string filename = Path.GetRandomFileName();
string filepath = Path.Combine(path, filename);
System.IO.File.WriteAllBytes(filepath, bytes);
}
}
static void CreateSummaryFile(string path)
{
string[] files = System.IO.Directory.GetFiles(path);
Parallel.ForEach(files, (file) =>
{
Thread.SpinWait(5000);
});
System.IO.File.WriteAllText(Path.Combine(path, "__SummaryFile.txt"), "did my work");
Console.WriteLine("Done with task2");
}
static void SimpleContinuationWithState()
{
int[] nums = { 19, 17, 21, 4, 13, 8, 12, 7, 3, 5 };
var f0 = new Task<double>(() => nums.Average());
var f1 = f0.ContinueWith( t => GetStandardDeviation(nums, t.Result));
f0.Start();
Console.WriteLine("the standard deviation is {0}", f1.Result);
}
private static double GetStandardDeviation(int[] values, double mean)
{
double d = 0.0;
foreach (var n in values)
{
d += Math.Pow(mean - n, 2);
}
return Math.Sqrt(d / (values.Length - 1));
}
}
}
Il parametro di tipo di Task<TResult> determina il tipo restituito del delegato. Questo valore restituito viene passato all'attività di continuazione. In questo modo è possibile concatenare un numero arbitrario di attività.
Vedere anche
Concetti
Programmazione parallela in .NET Framework
Espressioni lambda in PLINQ e TPL