Procedure: voorkomen dat een onderliggende taak wordt gekoppeld aan het bovenliggende item
In dit document ziet u hoe u kunt voorkomen dat een onderliggende taak wordt gekoppeld aan de bovenliggende taak. Voorkomen dat een onderliggende taak aan het bovenliggende element wordt gekoppeld, is handig wanneer u een onderdeel aanroept dat is geschreven door een derde partij en die ook taken gebruikt. Een onderdeel van derden dat gebruikmaakt van de TaskCreationOptions.AttachedToParent optie om een Task of Task<TResult> ander object te maken, kan bijvoorbeeld problemen veroorzaken in uw code als deze langlopend is of een onverwerkte uitzondering genereert.
Opmerking
In het volgende voorbeeld worden de effecten van het gebruik van de standaardopties vergeleken met de effecten van het voorkomen dat een onderliggende taak aan het bovenliggende item wordt gekoppeld. In het voorbeeld wordt een Task object gemaakt dat wordt aangeroepen in een bibliotheek van derden die ook gebruikmaakt van een Task object. De bibliotheek van derden gebruikt de AttachedToParent optie om het Task object te maken. De toepassing gebruikt de TaskCreationOptions.DenyChildAttach optie om de bovenliggende taak te maken. Met deze optie wordt de runtime geïnstrueerd om de AttachedToParent specificatie in onderliggende taken te verwijderen.
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
// Defines functionality that is provided by a third-party.
// In a real-world scenario, this would likely be provided
// in a separate code file or assembly.
namespace Contoso
{
public class Widget
{
public Task Run()
{
// Create a long-running task that is attached to the
// parent in the task hierarchy.
return Task.Factory.StartNew(() =>
{
// Simulate a lengthy operation.
Thread.Sleep(5000);
}, TaskCreationOptions.AttachedToParent);
}
}
}
// Demonstrates how to prevent a child task from attaching to the parent.
class DenyChildAttach
{
static void RunWidget(Contoso.Widget widget,
TaskCreationOptions parentTaskOptions)
{
// Record the time required to run the parent
// and child tasks.
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Console.WriteLine("Starting widget as a background task...");
// Run the widget task in the background.
Task<Task> runWidget = Task.Factory.StartNew(() =>
{
Task widgetTask = widget.Run();
// Perform other work while the task runs...
Thread.Sleep(1000);
return widgetTask;
}, parentTaskOptions);
// Wait for the parent task to finish.
Console.WriteLine("Waiting for parent task to finish...");
runWidget.Wait();
Console.WriteLine("Parent task has finished. Elapsed time is {0} ms.",
stopwatch.ElapsedMilliseconds);
// Perform more work...
Console.WriteLine("Performing more work on the main thread...");
Thread.Sleep(2000);
Console.WriteLine("Elapsed time is {0} ms.", stopwatch.ElapsedMilliseconds);
// Wait for the child task to finish.
Console.WriteLine("Waiting for child task to finish...");
runWidget.Result.Wait();
Console.WriteLine("Child task has finished. Elapsed time is {0} ms.",
stopwatch.ElapsedMilliseconds);
}
static void Main(string[] args)
{
Contoso.Widget w = new Contoso.Widget();
// Perform the same operation two times. The first time, the operation
// is performed by using the default task creation options. The second
// time, the operation is performed by using the DenyChildAttach option
// in the parent task.
Console.WriteLine("Demonstrating parent/child tasks with default options...");
RunWidget(w, TaskCreationOptions.None);
Console.WriteLine();
Console.WriteLine("Demonstrating parent/child tasks with the DenyChildAttach option...");
RunWidget(w, TaskCreationOptions.DenyChildAttach);
}
}
/* Sample output:
Demonstrating parent/child tasks with default options...
Starting widget as a background task...
Waiting for parent task to finish...
Parent task has finished. Elapsed time is 5014 ms.
Performing more work on the main thread...
Elapsed time is 7019 ms.
Waiting for child task to finish...
Child task has finished. Elapsed time is 7019 ms.
Demonstrating parent/child tasks with the DenyChildAttach option...
Starting widget as a background task...
Waiting for parent task to finish...
Parent task has finished. Elapsed time is 1007 ms.
Performing more work on the main thread...
Elapsed time is 3015 ms.
Waiting for child task to finish...
Child task has finished. Elapsed time is 5015 ms.
*/
Imports System.Diagnostics
Imports System.Threading
Imports System.Threading.Tasks
' Defines functionality that is provided by a third-party.
' In a real-world scenario, this would likely be provided
' in a separate code file or assembly.
Namespace Contoso
Public Class Widget
Public Function Run() As Task
' Create a long-running task that is attached to the
' parent in the task hierarchy.
Return Task.Factory.StartNew(Sub() Thread.Sleep(5000), TaskCreationOptions.AttachedToParent)
' Simulate a lengthy operation.
End Function
End Class
End Namespace
' Demonstrates how to prevent a child task from attaching to the parent.
Friend Class DenyChildAttach
Private Shared Sub RunWidget(ByVal widget As Contoso.Widget, ByVal parentTaskOptions As TaskCreationOptions)
' Record the time required to run the parent
' and child tasks.
Dim stopwatch As New Stopwatch()
stopwatch.Start()
Console.WriteLine("Starting widget as a background task...")
' Run the widget task in the background.
Dim runWidget As Task(Of Task) = Task.Factory.StartNew(Function()
' Perform other work while the task runs...
Dim widgetTask As Task = widget.Run()
Thread.Sleep(1000)
Return widgetTask
End Function, parentTaskOptions)
' Wait for the parent task to finish.
Console.WriteLine("Waiting for parent task to finish...")
runWidget.Wait()
Console.WriteLine("Parent task has finished. Elapsed time is {0} ms.", stopwatch.ElapsedMilliseconds)
' Perform more work...
Console.WriteLine("Performing more work on the main thread...")
Thread.Sleep(2000)
Console.WriteLine("Elapsed time is {0} ms.", stopwatch.ElapsedMilliseconds)
' Wait for the child task to finish.
Console.WriteLine("Waiting for child task to finish...")
runWidget.Result.Wait()
Console.WriteLine("Child task has finished. Elapsed time is {0} ms.", stopwatch.ElapsedMilliseconds)
End Sub
Shared Sub Main(ByVal args() As String)
Dim w As New Contoso.Widget()
' Perform the same operation two times. The first time, the operation
' is performed by using the default task creation options. The second
' time, the operation is performed by using the DenyChildAttach option
' in the parent task.
Console.WriteLine("Demonstrating parent/child tasks with default options...")
RunWidget(w, TaskCreationOptions.None)
Console.WriteLine()
Console.WriteLine("Demonstrating parent/child tasks with the DenyChildAttach option...")
RunWidget(w, TaskCreationOptions.DenyChildAttach)
End Sub
End Class
' Sample output:
'Demonstrating parent/child tasks with default options...
'Starting widget as a background task...
'Waiting for parent task to finish...
'Parent task has finished. Elapsed time is 5014 ms.
'Performing more work on the main thread...
'Elapsed time is 7019 ms.
'Waiting for child task to finish...
'Child task has finished. Elapsed time is 7019 ms.
'
'Demonstrating parent/child tasks with the DenyChildAttach option...
'Starting widget as a background task...
'Waiting for parent task to finish...
'Parent task has finished. Elapsed time is 1007 ms.
'Performing more work on the main thread...
'Elapsed time is 3015 ms.
'Waiting for child task to finish...
'Child task has finished. Elapsed time is 5015 ms.
'
Omdat een bovenliggende taak pas wordt voltooid als alle onderliggende taken zijn voltooid, kan een langlopende onderliggende taak ertoe leiden dat de algehele toepassing slecht presteert. Wanneer de toepassing in dit voorbeeld de standaardopties gebruikt om de bovenliggende taak te maken, moet de onderliggende taak worden voltooid voordat de bovenliggende taak is voltooid. Wanneer de toepassing de TaskCreationOptions.DenyChildAttach optie gebruikt, wordt het onderliggende element niet gekoppeld aan het bovenliggende item. Daarom kan de toepassing extra werk uitvoeren nadat de bovenliggende taak is voltooid en voordat de onderliggende taak moet worden voltooid.