TaskScheduler Třída

Definice

Představuje objekt, který zpracovává práci v úlohách služby Řízení front na nízké úrovni na vlákna.Represents an object that handles the low-level work of queuing tasks onto threads.

public ref class TaskScheduler abstract
public abstract class TaskScheduler
type TaskScheduler = class
Public MustInherit Class TaskScheduler
Dědičnost
TaskScheduler

Příklady

Následující příklad je pořízen z ukázek pro paralelní programování s .NET Framework 4 na webu Galerie kódu na webu MSDN.The following example is taken from the Samples for Parallel Programming with the .NET Framework 4 on the MSDN Code Gallery Web site. Vytvoří vlastního plánovače úloh, který omezuje počet vláken používaných aplikací.It creates a custom task scheduler that limits the number of threads used by the app. Potom spustí dvě sady úloh a zobrazí informace o úloze a vlákně, na kterých je úloha prováděna.It then launches two sets of tasks and displays information about the task and the thread on which the task is executing.

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

class Example
{
   static void Main()
   {
       // Create a scheduler that uses two threads. 
       LimitedConcurrencyLevelTaskScheduler lcts = new LimitedConcurrencyLevelTaskScheduler(2);
       List<Task> tasks = new List<Task>();
       
       // Create a TaskFactory and pass it our custom scheduler. 
       TaskFactory factory = new TaskFactory(lcts);
       CancellationTokenSource cts = new CancellationTokenSource();
       
       // Use our factory to run a set of tasks. 
       Object lockObj = new Object();
       int outputItem = 0;
       
       for (int tCtr = 0; tCtr <= 4; tCtr++) {
          int iteration = tCtr;
          Task t = factory.StartNew(() => {
                                       for (int i = 0; i < 1000; i++) {
                                          lock (lockObj) {
                                             Console.Write("{0} in task t-{1} on thread {2}   ", 
                                                           i, iteration, Thread.CurrentThread.ManagedThreadId);
                                             outputItem++;
                                             if (outputItem % 3 == 0)
                                                Console.WriteLine();
                                          }
                                       }                   
                                    }, cts.Token);
          tasks.Add(t);                      
      }
      // Use it to run a second set of tasks.                       
      for (int tCtr = 0; tCtr <= 4; tCtr++) {
         int iteration = tCtr;
         Task t1 = factory.StartNew(() => {
                                       for (int outer = 0; outer <= 10; outer++) {
                                          for (int i = 0x21; i <= 0x7E; i++) {
                                             lock (lockObj) {
                                                Console.Write("'{0}' in task t1-{1} on thread {2}   ", 
                                                              Convert.ToChar(i), iteration, Thread.CurrentThread.ManagedThreadId);
                                                outputItem++;
                                                if (outputItem % 3 == 0)
                                                   Console.WriteLine();
                                             } 
                                          }
                                       }                                           
                                    }, cts.Token);           
         tasks.Add(t1);
      }
      
      // Wait for the tasks to complete before displaying a completion message.
      Task.WaitAll(tasks.ToArray());
      cts.Dispose();
      Console.WriteLine("\n\nSuccessful completion.");
   }
}

// Provides a task scheduler that ensures a maximum concurrency level while 
// running on top of the thread pool.
public class LimitedConcurrencyLevelTaskScheduler : TaskScheduler
{
   // Indicates whether the current thread is processing work items.
   [ThreadStatic]
   private static bool _currentThreadIsProcessingItems;

  // The list of tasks to be executed 
   private readonly LinkedList<Task> _tasks = new LinkedList<Task>(); // protected by lock(_tasks)

   // The maximum concurrency level allowed by this scheduler. 
   private readonly int _maxDegreeOfParallelism;

   // Indicates whether the scheduler is currently processing work items. 
   private int _delegatesQueuedOrRunning = 0;

   // Creates a new instance with the specified degree of parallelism. 
   public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism)
   {
       if (maxDegreeOfParallelism < 1) throw new ArgumentOutOfRangeException("maxDegreeOfParallelism");
       _maxDegreeOfParallelism = maxDegreeOfParallelism;
   }

   // Queues a task to the scheduler. 
   protected sealed override void QueueTask(Task task)
   {
      // Add the task to the list of tasks to be processed.  If there aren't enough 
      // delegates currently queued or running to process tasks, schedule another. 
       lock (_tasks)
       {
           _tasks.AddLast(task);
           if (_delegatesQueuedOrRunning < _maxDegreeOfParallelism)
           {
               ++_delegatesQueuedOrRunning;
               NotifyThreadPoolOfPendingWork();
           }
       }
   }

   // Inform the ThreadPool that there's work to be executed for this scheduler. 
   private void NotifyThreadPoolOfPendingWork()
   {
       ThreadPool.UnsafeQueueUserWorkItem(_ =>
       {
           // Note that the current thread is now processing work items.
           // This is necessary to enable inlining of tasks into this thread.
           _currentThreadIsProcessingItems = true;
           try
           {
               // Process all available items in the queue.
               while (true)
               {
                   Task item;
                   lock (_tasks)
                   {
                       // When there are no more items to be processed,
                       // note that we're done processing, and get out.
                       if (_tasks.Count == 0)
                       {
                           --_delegatesQueuedOrRunning;
                           break;
                       }

                       // Get the next item from the queue
                       item = _tasks.First.Value;
                       _tasks.RemoveFirst();
                   }

                   // Execute the task we pulled out of the queue
                   base.TryExecuteTask(item);
               }
           }
           // We're done processing items on the current thread
           finally { _currentThreadIsProcessingItems = false; }
       }, null);
   }

   // Attempts to execute the specified task on the current thread. 
   protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
   {
       // If this thread isn't already processing a task, we don't support inlining
       if (!_currentThreadIsProcessingItems) return false;

       // If the task was previously queued, remove it from the queue
       if (taskWasPreviouslyQueued) 
          // Try to run the task. 
          if (TryDequeue(task)) 
            return base.TryExecuteTask(task);
          else
             return false; 
       else 
          return base.TryExecuteTask(task);
   }

   // Attempt to remove a previously scheduled task from the scheduler. 
   protected sealed override bool TryDequeue(Task task)
   {
       lock (_tasks) return _tasks.Remove(task);
   }

   // Gets the maximum concurrency level supported by this scheduler. 
   public sealed override int MaximumConcurrencyLevel { get { return _maxDegreeOfParallelism; } }

   // Gets an enumerable of the tasks currently scheduled on this scheduler. 
   protected sealed override IEnumerable<Task> GetScheduledTasks()
   {
       bool lockTaken = false;
       try
       {
           Monitor.TryEnter(_tasks, ref lockTaken);
           if (lockTaken) return _tasks;
           else throw new NotSupportedException();
       }
       finally
       {
           if (lockTaken) Monitor.Exit(_tasks);
       }
   }
}
// The following is a portion of the output from a single run of the example:
//    'T' in task t1-4 on thread 3   'U' in task t1-4 on thread 3   'V' in task t1-4 on thread 3   
//    'W' in task t1-4 on thread 3   'X' in task t1-4 on thread 3   'Y' in task t1-4 on thread 3   
//    'Z' in task t1-4 on thread 3   '[' in task t1-4 on thread 3   '\' in task t1-4 on thread 3   
//    ']' in task t1-4 on thread 3   '^' in task t1-4 on thread 3   '_' in task t1-4 on thread 3   
//    '`' in task t1-4 on thread 3   'a' in task t1-4 on thread 3   'b' in task t1-4 on thread 3   
//    'c' in task t1-4 on thread 3   'd' in task t1-4 on thread 3   'e' in task t1-4 on thread 3   
//    'f' in task t1-4 on thread 3   'g' in task t1-4 on thread 3   'h' in task t1-4 on thread 3   
//    'i' in task t1-4 on thread 3   'j' in task t1-4 on thread 3   'k' in task t1-4 on thread 3   
//    'l' in task t1-4 on thread 3   'm' in task t1-4 on thread 3   'n' in task t1-4 on thread 3   
//    'o' in task t1-4 on thread 3   'p' in task t1-4 on thread 3   ']' in task t1-2 on thread 4   
//    '^' in task t1-2 on thread 4   '_' in task t1-2 on thread 4   '`' in task t1-2 on thread 4   
//    'a' in task t1-2 on thread 4   'b' in task t1-2 on thread 4   'c' in task t1-2 on thread 4   
//    'd' in task t1-2 on thread 4   'e' in task t1-2 on thread 4   'f' in task t1-2 on thread 4   
//    'g' in task t1-2 on thread 4   'h' in task t1-2 on thread 4   'i' in task t1-2 on thread 4   
//    'j' in task t1-2 on thread 4   'k' in task t1-2 on thread 4   'l' in task t1-2 on thread 4   
//    'm' in task t1-2 on thread 4   'n' in task t1-2 on thread 4   'o' in task t1-2 on thread 4   
//    'p' in task t1-2 on thread 4   'q' in task t1-2 on thread 4   'r' in task t1-2 on thread 4   
//    's' in task t1-2 on thread 4   't' in task t1-2 on thread 4   'u' in task t1-2 on thread 4   
//    'v' in task t1-2 on thread 4   'w' in task t1-2 on thread 4   'x' in task t1-2 on thread 4   
//    'y' in task t1-2 on thread 4   'z' in task t1-2 on thread 4   '{' in task t1-2 on thread 4   
//    '|' in task t1-2 on thread 4   '}' in task t1-2 on thread 4   '~' in task t1-2 on thread 4   
//    'q' in task t1-4 on thread 3   'r' in task t1-4 on thread 3   's' in task t1-4 on thread 3   
//    't' in task t1-4 on thread 3   'u' in task t1-4 on thread 3   'v' in task t1-4 on thread 3   
//    'w' in task t1-4 on thread 3   'x' in task t1-4 on thread 3   'y' in task t1-4 on thread 3   
//    'z' in task t1-4 on thread 3   '{' in task t1-4 on thread 3   '|' in task t1-4 on thread 3  
Imports System.Collections.Generic
Imports System.Threading
Imports System.Threading.Tasks

Module Example
   Sub Main()
      ' Create a scheduler that uses two threads. 
      Dim lcts As New LimitedConcurrencyLevelTaskScheduler(2)
      Dim tasks As New List(Of Task)()
      
      ' Create a TaskFactory and pass it our custom scheduler. 
      Dim factory As New TaskFactory(lcts)
      Dim cts As New CancellationTokenSource()
      
      ' Use our factory to run a set of tasks. 
      Dim objLock As New Object()      
      Dim outputItem As Integer 
      For tCtr As Integer = 0 To 4
         Dim iteration As Integer = tCtr
         Dim t As Task = factory.StartNew(Sub()
                                             For i As Integer = 1 To 1000
                                                SyncLock objLock
                                                   Console.Write("{0} in task t-{1} on thread {2}   ", 
                                                   i, iteration, Thread.CurrentThread.ManagedThreadId)
                                                   outputItem += 1
                                                   If outputItem Mod 3 = 0 Then Console.WriteLine()
                                                End SyncLock
                                             Next 
                                          End Sub,
                                cts.Token)
         tasks.Add(t)
      Next 
      ' Use it to run a second set of tasks.                       
      For tCtr As Integer = 0 To 4
         Dim iteration As Integer = tCtr
         Dim t1 As Task = factory.StartNew(Sub()
                                              For outer As Integer = 0 To 10
                                                 For i As Integer = &h21 To &h7E
                                                    SyncLock objLock
                                                       Console.Write("'{0}' in task t1-{1} on thread {2}   ", 
                                                                     Convert.ToChar(i), iteration, Thread.CurrentThread.ManagedThreadId)
                                                       outputItem += 1
                                                       If outputItem Mod 3 = 0 Then Console.WriteLine()
                                                    End SyncLock 
                                                 Next     
                                              Next                                           
                                           End Sub,
                                cts.Token)           
         tasks.Add(t1)
      Next
      
      ' Wait for the tasks to complete before displaying a completion message.
      Task.WaitAll(tasks.ToArray())
      cts.Dispose()
      Console.WriteLine(vbCrLf + vbCrLf + "Successful completion.")
   End Sub 
End Module

' Provides a task scheduler that ensures a maximum concurrency level while 
' running on top of the thread pool.
Public Class LimitedConcurrencyLevelTaskScheduler : Inherits TaskScheduler
   ' Indicates whether the current thread is processing work items.
   <ThreadStatic()> Private Shared _currentThreadIsProcessingItems As Boolean 
   
   ' The list of tasks to be executed 
   Private ReadOnly _tasks As LinkedList(Of Task) = New LinkedList(Of Task)() 
   
   'The maximum concurrency level allowed by this scheduler. 
   Private ReadOnly _maxDegreeOfParallelism As Integer 
   
   ' Indicates whether the scheduler is currently processing work items. 
   Private _delegatesQueuedOrRunning As Integer = 0 ' protected by lock(_tasks)
   
   ' Creates a new instance with the specified degree of parallelism. 
   Public Sub New(ByVal maxDegreeOfParallelism As Integer)
      If (maxDegreeOfParallelism < 1) Then 
         Throw New ArgumentOutOfRangeException("maxDegreeOfParallelism")
      End If
         _maxDegreeOfParallelism = maxDegreeOfParallelism
   End Sub 

   ' Queues a task to the scheduler. 
   Protected Overrides Sub QueueTask(ByVal t As Task)
      ' Add the task to the list of tasks to be processed.  If there aren't enough 
      ' delegates currently queued or running to process tasks, schedule another. 
      SyncLock (_tasks)
         _tasks.AddLast(t)
         If (_delegatesQueuedOrRunning < _maxDegreeOfParallelism) Then
            _delegatesQueuedOrRunning = _delegatesQueuedOrRunning + 1
            NotifyThreadPoolOfPendingWork()
         End If 
      End SyncLock 
   End Sub 
   
   ' Inform the ThreadPool that there's work to be executed for this scheduler. 
   Private Sub NotifyThreadPoolOfPendingWork()
   
      ThreadPool.UnsafeQueueUserWorkItem(Sub()
                                            ' Note that the current thread is now processing work items. 
                                            ' This is necessary to enable inlining of tasks into this thread.
                                            _currentThreadIsProcessingItems = True 
                                            Try 
                                               ' Process all available items in the queue. 
                                               While (True)
                                                  Dim item As Task
                                                  SyncLock (_tasks)
                                                     ' When there are no more items to be processed, 
                                                     ' note that we're done processing, and get out. 
                                                     If (_tasks.Count = 0) Then
                                                        _delegatesQueuedOrRunning = _delegatesQueuedOrRunning - 1
                                                        Exit While 
                                                     End If 
   
                                                     ' Get the next item from the queue
                                                     item = _tasks.First.Value
                                                     _tasks.RemoveFirst()
                                                  End SyncLock 
   
                                                  ' Execute the task we pulled out of the queue 
                                                  MyBase.TryExecuteTask(item)
                                               End While 
                                               ' We're done processing items on the current thread 
                                            Finally
                                               _currentThreadIsProcessingItems = False 
                                            End Try 
                                         End Sub,
                                    Nothing)
   End Sub 
   
   ' Attempts to execute the specified task on the current thread. 
   Protected Overrides Function TryExecuteTaskInline(ByVal t As Task, 
                                                     ByVal taskWasPreviouslyQueued As Boolean) As Boolean 
      ' If this thread isn't already processing a task, we don't support inlining 
      If (Not _currentThreadIsProcessingItems) Then 
         Return False 
      End If 
   
      ' If the task was previously queued, remove it from the queue 
      If (taskWasPreviouslyQueued) Then
         ' Try to run the task. 
         If TryDequeue(t) Then 
            Return MyBase.TryExecuteTask(t)
         Else
            Return False 
         End If     
      Else 
         Return MyBase.TryExecuteTask(t)
      End If   
   End Function 
   
   ' Attempt to remove a previously scheduled task from the scheduler. 
   Protected Overrides Function TryDequeue(ByVal t As Task) As Boolean 
      SyncLock (_tasks)
         Return _tasks.Remove(t)
      End SyncLock 
   End Function 
   
   ' Gets the maximum concurrency level supported by this scheduler. 
   Public Overrides ReadOnly Property MaximumConcurrencyLevel As Integer 
      Get 
         Return _maxDegreeOfParallelism
      End Get 
   End Property 
   
   ' Gets an enumerable of the tasks currently scheduled on this scheduler. 
   Protected Overrides Function GetScheduledTasks() As IEnumerable(Of Task)
      Dim lockTaken As Boolean = False 
      Try
         Monitor.TryEnter(_tasks, lockTaken)
         If (lockTaken) Then 
            Return _tasks.ToArray()
         Else 
            Throw New NotSupportedException()
         End If 
      Finally 
         If (lockTaken) Then
            Monitor.Exit(_tasks)
         End If 
      End Try 
   End Function 
End Class 
' The following is a portion of the output from a single run of the example:
'    'T' in task t1-4 on thread 3   'U' in task t1-4 on thread 3   'V' in task t1-4 on thread 3   
'    'W' in task t1-4 on thread 3   'X' in task t1-4 on thread 3   'Y' in task t1-4 on thread 3   
'    'Z' in task t1-4 on thread 3   '[' in task t1-4 on thread 3   '\' in task t1-4 on thread 3   
'    ']' in task t1-4 on thread 3   '^' in task t1-4 on thread 3   '_' in task t1-4 on thread 3   
'    '`' in task t1-4 on thread 3   'a' in task t1-4 on thread 3   'b' in task t1-4 on thread 3   
'    'c' in task t1-4 on thread 3   'd' in task t1-4 on thread 3   'e' in task t1-4 on thread 3   
'    'f' in task t1-4 on thread 3   'g' in task t1-4 on thread 3   'h' in task t1-4 on thread 3   
'    'i' in task t1-4 on thread 3   'j' in task t1-4 on thread 3   'k' in task t1-4 on thread 3   
'    'l' in task t1-4 on thread 3   'm' in task t1-4 on thread 3   'n' in task t1-4 on thread 3   
'    'o' in task t1-4 on thread 3   'p' in task t1-4 on thread 3   ']' in task t1-2 on thread 4   
'    '^' in task t1-2 on thread 4   '_' in task t1-2 on thread 4   '`' in task t1-2 on thread 4   
'    'a' in task t1-2 on thread 4   'b' in task t1-2 on thread 4   'c' in task t1-2 on thread 4   
'    'd' in task t1-2 on thread 4   'e' in task t1-2 on thread 4   'f' in task t1-2 on thread 4   
'    'g' in task t1-2 on thread 4   'h' in task t1-2 on thread 4   'i' in task t1-2 on thread 4   
'    'j' in task t1-2 on thread 4   'k' in task t1-2 on thread 4   'l' in task t1-2 on thread 4   
'    'm' in task t1-2 on thread 4   'n' in task t1-2 on thread 4   'o' in task t1-2 on thread 4   
'    'p' in task t1-2 on thread 4   'q' in task t1-2 on thread 4   'r' in task t1-2 on thread 4   
'    's' in task t1-2 on thread 4   't' in task t1-2 on thread 4   'u' in task t1-2 on thread 4   
'    'v' in task t1-2 on thread 4   'w' in task t1-2 on thread 4   'x' in task t1-2 on thread 4   
'    'y' in task t1-2 on thread 4   'z' in task t1-2 on thread 4   '{' in task t1-2 on thread 4   
'    '|' in task t1-2 on thread 4   '}' in task t1-2 on thread 4   '~' in task t1-2 on thread 4   
'    'q' in task t1-4 on thread 3   'r' in task t1-4 on thread 3   's' in task t1-4 on thread 3   
'    't' in task t1-4 on thread 3   'u' in task t1-4 on thread 3   'v' in task t1-4 on thread 3   
'    'w' in task t1-4 on thread 3   'x' in task t1-4 on thread 3   'y' in task t1-4 on thread 3   
'    'z' in task t1-4 on thread 3   '{' in task t1-4 on thread 3   '|' in task t1-4 on thread 3  

Kromě toho jsou v galerii kódu k dispozici několik ukázkových plánovačů úloh: ukázky pro paralelní programování s .NET Framework 4.In addition, several sample task schedulers are available on Code Gallery: Samples for Parallel Programming with the .NET Framework 4.

Poznámky

Instance třídy TaskScheduler představuje Plánovač úloh.An instance of the TaskScheduler class represents a task scheduler. Plánovač úloh zajišťuje, že se úloha úlohy nakonec spustí.A task scheduler ensures that the work of a task is eventually executed.

Výchozí Plánovač úloh je založený na fondu vláken .NET Framework 4, který poskytuje krádeže vyrovnávání zatížení, vkládání/vyřazení vlákna pro maximální propustnost a celkový dobrý výkon.The default task scheduler is based on the .NET Framework 4 thread pool, which provides work-stealing for load-balancing, thread injection/retirement for maximum throughput, and overall good performance. Ve většině scénářů by měl být dostačující.It should be sufficient for most scenarios.

Třída TaskScheduler slouží také jako bod rozšíření pro veškerou přizpůsobitelnou logiku plánování.The TaskScheduler class also serves as the extension point for all customizable scheduling logic. To zahrnuje mechanismy, jako je například naplánování úlohy ke spuštění a způsob zpřístupnění plánovaných úloh ladicím programům.This includes mechanisms such as how to schedule a task for execution, and how scheduled tasks should be exposed to debuggers. Pokud požadujete zvláštní funkce, můžete vytvořit vlastní Plánovač a povolit ho pro konkrétní úkoly nebo dotazy.If you require special functionality, you can create a custom scheduler and enable it for specific tasks or queries.

V tomto tématu:In this topic:
Výchozí Plánovač úloh a fond vlákenThe default task scheduler and the thread pool
Globální fronta vs. místní frontyThe global queue vs. local queues
Odcizení práceWork stealing
Dlouhotrvající úlohyLong-running tasks
Vkládání úkolůTask inlining
Určení kontextu synchronizaceSpecifying a synchronization context

Výchozí Plánovač úloh a fond vlákenThe default task scheduler and the thread pool

Výchozí Plánovač pro Task Parallel Library a PLINQ používá fond vláken .NET Framework, který je reprezentován třídou ThreadPool, k zařazení do fronty a provedení práce.The default scheduler for the Task Parallel Library and PLINQ uses the .NET Framework thread pool, which is represented by the ThreadPool class, to queue and execute work. Fond vláken používá informace, které jsou poskytovány typem Task a efektivně tak podporují jemně odstupňované paralelismuy (krátkodobé pracovní jednotky), které často reprezentují Paralelní úlohy a dotazy.The thread pool uses the information that is provided by the Task type to efficiently support the fine-grained parallelism (short-lived units of work) that parallel tasks and queries often represent.

Globální fronta vs. místní frontyThe global queue vs. local queues

Fond vláken udržuje globální pracovní frontu FIFO (první v, první) pro vlákna v každé doméně aplikace.The thread pool maintains a global FIFO (first-in, first-out) work queue for threads in each application domain. Pokaždé, když program zavolá metodu ThreadPool.QueueUserWorkItem (nebo ThreadPool.UnsafeQueueUserWorkItem), práce se umístí do této sdílené fronty a nakonec se odřadí do fronty k dalšímu vláknu, které bude k dispozici.Whenever a program calls the ThreadPool.QueueUserWorkItem (or ThreadPool.UnsafeQueueUserWorkItem) method, the work is put on this shared queue and eventually de-queued onto the next thread that becomes available. Počínaje .NET Framework 4 byla tato fronta vylepšena tak, aby používala algoritmus bez zámků, který se podobá ConcurrentQueue<T> třídy.Starting with the .NET Framework 4, this queue has been improved to use a lock-free algorithm that resembles the ConcurrentQueue<T> class. Při použití této bezplatné implementace bez zámků fond vláken stráví méně času při frontách IT a odřadících pracovní položky.By using this lock-free implementation, the thread pool spends less time when it queues and de-queues work items. Tato výhoda výkonu je k dispozici pro všechny programy, které používají fond vláken.This performance benefit is available to all programs that use the thread pool.

Úkoly nejvyšší úrovně, které jsou úkoly, které nejsou vytvořeny v kontextu jiné úlohy, jsou vloženy do globální fronty stejně jako všechny jiné pracovní položky.Top-level tasks, which are tasks that are not created in the context of another task, are put on the global queue just like any other work item. Vnořené nebo podřízené úlohy, které jsou vytvořeny v kontextu jiné úlohy, jsou však zpracovávány velmi jinak.However, nested or child tasks, which are created in the context of another task, are handled quite differently. Podřízená nebo vnořená úloha je umístěna do místní fronty, která je specifická pro vlákno, na kterém je spuštěná nadřazená úloha.A child or nested task is put on a local queue that is specific to the thread on which the parent task is executing. Nadřazená úloha může být úkol nejvyšší úrovně, nebo může být podřízenou položkou jiné úlohy.The parent task may be a top-level task or it also may be the child of another task. Když je toto vlákno připravené na další práci, nejprve se vyhledá v místní frontě.When this thread is ready for more work, it first looks in the local queue. Pokud pracovní položky čekají na to, můžete k nim rychle přistup.If work items are waiting there, they can be accessed quickly. K místním frontám se přistupoval v rámci, jako je první (First-out Order), aby se zachovala možnost mezipamětí a omezila kolize obsahu.The local queues are accessed in last-in, first-out order (LIFO) to preserve cache locality and reduce contention. Další informace o podřízených úlohách a vnořených úlohách najdete v tématu připojené a odpojené podřízené úlohy.For more information about child tasks and nested tasks, see Attached and Detached Child Tasks.

Použití místních front nejen omezuje tlak na globální frontu, ale také využívá místní velikost dat.The use of local queues not only reduces pressure on the global queue, but also takes advantage of data locality. Pracovní položky v místní frontě často odkazují na datové struktury, které jsou fyzicky blízko sebe v paměti.Work items in the local queue frequently reference data structures that are physically near one another in memory. V těchto případech jsou data již v mezipaměti v po spuštění prvního úkolu a lze k němu rychle přistupovat.In these cases, the data is already in the cache after the first task has run and can be accessed quickly. Paralelní LINQ (PLINQ) i třída Parallel používají vnořené úlohy a podřízené úlohy intenzivně a dosahují významného urychlení pomocí místních pracovních front.Both Parallel LINQ (PLINQ) and the Parallel class use nested tasks and child tasks extensively, and achieve significant speedups by using the local work queues.

Odcizení práceWork stealing

Od .NET Framework 4 je fond vláken také vybavený algoritmem pro pracovní krádeži, který zajišťuje, aby žádná vlákna nefungovala v nečinné době, zatímco ostatní stále pracují ve svých frontách.Starting with the .NET Framework 4, the thread pool also features a work-stealing algorithm to help make sure that no threads are sitting idle while others still have work in their queues. Když je vlákno fondu vláken připravené na více práce, nejprve se podíváme na hlavní frontu, potom v globální frontě a potom v místních frontách jiných vláken.When a thread-pool thread is ready for more work, it first looks at the head of its local queue, then in the global queue, and then in the local queues of other threads. Pokud najde pracovní položku v místní frontě jiného vlákna, nejprve použije heuristiky k tomu, aby bylo zajištěno, že bude moci efektivně spustit práci.If it finds a work item in the local queue of another thread, it first applies heuristics to make sure that it can run the work efficiently. Pokud je to možné, odřadí pracovní položku z koncového bodu (v pořadí FIFO).If it can, it de-queues the work item from the tail (in FIFO order). Tím se snižuje počet kolizí u každé místní fronty a zachovává se jejich velikost.This reduces contention on each local queue and preserves data locality. Tato architektura pomáhá vyrovnávat zatížení fondu vláken efektivněji než minulé verze.This architecture helps the thread pool load-balance work more efficiently than past versions did.

Dlouhotrvající úlohyLong-running tasks

Je možné, že budete chtít explicitně zabránit tomu, aby byl úkol umístěn do místní fronty.You may want to explicitly prevent a task from being put on a local queue. Například může být známo, že konkrétní pracovní položka bude běžet poměrně dlouho a bude pravděpodobně zablokována všechny ostatní pracovní položky v místní frontě.For example, you may know that a particular work item will run for a relatively long time and is likely to block all other work items on the local queue. V tomto případě můžete zadat možnost System.Threading.Tasks.TaskCreationOptions, která poskytuje nápovědu pro Plánovač, že pro úlohu může být vyžadováno další vlákno, aby nedošlo k zablokování postupu před dalším vláknem nebo pracovními položkami v místní frontě.In this case, you can specify the System.Threading.Tasks.TaskCreationOptions option, which provides a hint to the scheduler that an additional thread might be required for the task so that it does not block the forward progress of other threads or work items on the local queue. Když použijete tuto možnost, vyhnete se úplnému fondu vláken, včetně globálních a místních front.By using this option you avoid the thread pool completely, including the global and local queues.

Vkládání úkolůTask inlining

V některých případech, pokud Task čeká na, může být proveden synchronně ve vlákně, které provádí operaci čekání.In some cases when a Task is waited on, it may be executed synchronously on the thread that is performing the wait operation. Tím se zlepší výkon tím, že se zabrání nutnosti dalšího vlákna a místo toho se použije existující vlákno, které by bylo zablokované jinak.This enhances performance by preventing the need for an additional thread and instead using the existing thread, which would have blocked otherwise. Aby se zabránilo chybám způsobeným Vícenásobný přístup, je vkládání úkolů provedeno pouze v případě, že je cíl čekání nalezen v místní frontě daného vlákna.To prevent errors due to reentrancy, task inlining only occurs when the wait target is found in the relevant thread's local queue.

Určení kontextu synchronizaceSpecifying a synchronization context

Metodu TaskScheduler.FromCurrentSynchronizationContext lze použít k určení, zda má být úloha naplánována pro spuštění v konkrétním vlákně.You can use the TaskScheduler.FromCurrentSynchronizationContext method to specify that a task should be scheduled to run on a particular thread. To je užitečné v rozhraních, jako je například model Windows Forms a Windows Presentation Foundation, kde je přístup k objektům uživatelského rozhraní často omezen na kód, který je spuštěn ve stejném vlákně, v němž byl objekt uživatelského rozhraní vytvořen.This is useful in frameworks such as Windows Forms and Windows Presentation Foundation where access to user interface objects is often restricted to code that is running on the same thread on which the UI object was created.

Následující příklad používá metodu TaskScheduler.FromCurrentSynchronizationContext v aplikaci Windows Presentation Foundation (WPF) k naplánování úlohy ve stejném vlákně, ve kterém byl ovládací prvek uživatelského rozhraní (UI) vytvořen.The following example uses the TaskScheduler.FromCurrentSynchronizationContext method in a Windows Presentation Foundation (WPF) app to schedule a task on the same thread that the user interface (UI) control was created on. Příklad vytvoří mozaika obrázků, které jsou náhodně vybírány ze zadaného adresáře.The example creates a mosaic of images that are randomly selected from a specified directory. Objekty WPF slouží k načtení a změně velikosti imagí.The WPF objects are used to load and resize the images. Nezpracované pixely jsou poté předány úkolu, který používá smyčku For k zápisu dat obrazových bodů do velkých jednobajtových polí.The raw pixels are then passed to a task that uses a For loop to write the pixel data into a large single-byte array. Není nutná žádná synchronizace, protože žádné dvě dlaždice nezaujímají stejné prvky pole.No synchronization is required because no two tiles occupy the same array elements. Dlaždice lze také zapsat v libovolném pořadí, protože jejich poloha je počítána nezávisle na jakékoli jiné dlaždici.The tiles can also be written in any order because their position is calculated independently of any other tile. Velké pole je pak předáno úkolu, který běží ve vlákně uživatelského rozhraní, kde jsou data v pixelech načtena do ovládacího prvku obrázek.The large array is then passed to a task that runs on the UI thread, where the pixel data is loaded into an Image control.

Příklad přesouvá data mimo vlákno uživatelského rozhraní, upravuje je pomocí paralelních smyček a Task objektů a pak je předává zpět do úlohy, která běží ve vlákně uživatelského rozhraní.The example moves data off the UI thread, modifies it by using parallel loops and Task objects, and then passes it back to a task that runs on the UI thread. Tento přístup je užitečný v případě, že je nutné použít úlohu Parallel Library k provádění operací, které rozhraní WPF API nepodporuje, nebo nejsou dostatečně rychlé.This approach is useful when you have to use the Task Parallel Library to perform operations that either are not supported by the WPF API, or are not sufficiently fast. Dalším způsobem, jak vytvořit obrazovou mozaika v WPF, je použít ovládací prvek System.Windows.Controls.WrapPanel a přidat do něj obrázky.Another way to create an image mosaic in WPF is to use a System.Windows.Controls.WrapPanel control and add images to it. WrapPanel zpracovává práci při umísťování dlaždic.The WrapPanel handles the work of positioning the tiles. Tuto práci však lze provést pouze ve vlákně uživatelského rozhraní.However, this work can only be performed on the UI thread.

using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace WPF_CS1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private int fileCount;
        int colCount;
        int rowCount;
        private int tilePixelHeight;
        private int tilePixelWidth;
        private int largeImagePixelHeight;
        private int largeImagePixelWidth;
        private int largeImageStride;
        PixelFormat format;
        BitmapPalette palette = null;

        public MainWindow()
        {
            InitializeComponent();

            // For this example, values are hard-coded to a mosaic of 8x8 tiles.
            // Each tile is 50 pixels high and 66 pixels wide and 32 bits per pixel.
            colCount = 12;
            rowCount = 8;
            tilePixelHeight = 50;
            tilePixelWidth = 66;
            largeImagePixelHeight = tilePixelHeight * rowCount;
            largeImagePixelWidth = tilePixelWidth * colCount;
            largeImageStride = largeImagePixelWidth * (32 / 8);
            this.Width = largeImagePixelWidth + 40;
            image.Width = largeImagePixelWidth;
            image.Height = largeImagePixelHeight;

        }

        private void button_Click(object sender, RoutedEventArgs e)
        {

            // For best results use 1024 x 768 jpg files at 32bpp.
            string[] files = System.IO.Directory.GetFiles(@"C:\Users\Public\Pictures\Sample Pictures\", "*.jpg");

            fileCount = files.Length;
            Task<byte[]>[] images = new Task<byte[]>[fileCount];
            for (int i = 0; i < fileCount; i++)
            {
                int x = i;
                images[x] = Task.Factory.StartNew(() => LoadImage(files[x]));
            }

            // When they've all been loaded, tile them into a single byte array.
            var tiledImage = Task.Factory.ContinueWhenAll(
                images, (i) => TileImages(i));

            // We are currently on the UI thread. Save the sync context and pass it to
            // the next task so that it can access the UI control "image".
            var UISyncContext = TaskScheduler.FromCurrentSynchronizationContext();

            // On the UI thread, put the bytes into a bitmap and
            // display it in the Image control.
            var t3 = tiledImage.ContinueWith((antecedent) =>
            {
                // Get System DPI.
                Matrix m = PresentationSource.FromVisual(Application.Current.MainWindow)
                                            .CompositionTarget.TransformToDevice;
                double dpiX = m.M11;
                double dpiY = m.M22;

                BitmapSource bms = BitmapSource.Create(largeImagePixelWidth,
                    largeImagePixelHeight,
                    dpiX,
                    dpiY,
                    format,
                    palette, //use default palette
                    antecedent.Result,
                    largeImageStride);
                image.Source = bms;
            }, UISyncContext);
        }

        byte[] LoadImage(string filename)
        {
            // Use the WPF BitmapImage class to load and 
            // resize the bitmap. NOTE: Only 32bpp formats are supported correctly.
            // Support for additional color formats is left as an exercise
            // for the reader. For more information, see documentation for ColorConvertedBitmap.

            BitmapImage bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            bitmapImage.UriSource = new Uri(filename);
            bitmapImage.DecodePixelHeight = tilePixelHeight;
            bitmapImage.DecodePixelWidth = tilePixelWidth;
            bitmapImage.EndInit();

            format = bitmapImage.Format;
            int size = (int)(bitmapImage.Height * bitmapImage.Width);
            int stride = (int)bitmapImage.Width * 4;
            byte[] dest = new byte[stride * tilePixelHeight];

            bitmapImage.CopyPixels(dest, stride, 0);

            return dest;
        }

        int Stride(int pixelWidth, int bitsPerPixel)
        {
            return (((pixelWidth * bitsPerPixel + 31) / 32) * 4);
        }

        // Map the individual image tiles to the large image
        // in parallel. Any kind of raw image manipulation can be
        // done here because we are not attempting to access any 
        // WPF controls from multiple threads.
        byte[] TileImages(Task<byte[]>[] sourceImages)
        {
            byte[] largeImage = new byte[largeImagePixelHeight * largeImageStride];
            int tileImageStride = tilePixelWidth * 4; // hard coded to 32bpp

            Random rand = new Random();
            Parallel.For(0, rowCount * colCount, (i) =>
            {
                // Pick one of the images at random for this tile.
                int cur = rand.Next(0, sourceImages.Length);
                byte[] pixels = sourceImages[cur].Result;

                // Get the starting index for this tile.
                int row = i / colCount;
                int col = (int)(i % colCount);
                int idx = ((row * (largeImageStride * tilePixelHeight)) + (col * tileImageStride));

                // Write the pixels for the current tile. The pixels are not contiguous
                // in the array, therefore we have to advance the index by the image stride
                // (minus the stride of the tile) for each scanline of the tile.
                int tileImageIndex = 0;
                for (int j = 0; j < tilePixelHeight; j++)
                {
                    // Write the next scanline for this tile.
                    for (int k = 0; k < tileImageStride; k++)
                    {
                        largeImage[idx++] = pixels[tileImageIndex++];
                    }
                    // Advance to the beginning of the next scanline.
                    idx += largeImageStride - tileImageStride;
                }
            });
            return largeImage;
        }
    }
}
Imports System.Threading.Tasks
Imports System.Windows
Imports System.Windows.Media
Imports System.Windows.Media.Imaging

Partial Public Class MainWindow : Inherits Window
    Dim fileCount As Integer
    Dim colCount As Integer
    Dim rowCount As Integer
    Dim tilePixelHeight As Integer
    Dim tilePixelWidth As Integer
    Dim largeImagePixelHeight As Integer
    Dim largeImagePixelWidth As Integer
    Dim largeImageStride As Integer
    Dim format As PixelFormat
    Dim palette As BitmapPalette = Nothing

    Public Sub New()
        InitializeComponent()

        ' For this example, values are hard-coded to a mosaic of 8x8 tiles.
        ' Each tile Is 50 pixels high and 66 pixels wide and 32 bits per pixel.
        colCount = 12
        rowCount = 8
        tilePixelHeight = 50
        tilePixelWidth = 66
        largeImagePixelHeight = tilePixelHeight * rowCount
        largeImagePixelWidth = tilePixelWidth * colCount
        largeImageStride = largeImagePixelWidth * (32 / 8)
        Me.Width = largeImagePixelWidth + 40
        image.Width = largeImagePixelWidth
        image.Height = largeImagePixelHeight
    End Sub

    Private Sub button_Click(sender As Object, e As RoutedEventArgs) _
        Handles button.Click

        ' For best results use 1024 x 768 jpg files at 32bpp.
        Dim files() As String = System.IO.Directory.GetFiles("C:\Users\Public\Pictures\Sample Pictures\", "*.jpg")

        fileCount = files.Length
        Dim images(fileCount - 1) As Task(Of Byte())
        For i As Integer = 0 To fileCount - 1
            Dim x As Integer = i
            images(x) = Task.Factory.StartNew(Function() LoadImage(files(x)))
        Next

        ' When they have all been loaded, tile them into a single byte array.
        'var tiledImage = Task.Factory.ContinueWhenAll(
        '        images, (i) >= TileImages(i));

        '        Dim tiledImage As Task(Of Byte()) = Task.Factory.ContinueWhenAll(images, Function(i As Task(Of Byte())) TileImages(i))
        Dim tiledImage = Task.Factory.ContinueWhenAll(images, Function(i As Task(Of Byte())()) TileImages(i))
        ' We are currently on the UI thread. Save the sync context and pass it to
        ' the next task so that it can access the UI control "image1".
        Dim UISyncContext = TaskScheduler.FromCurrentSynchronizationContext()

        ' On the UI thread, put the bytes into a bitmap and
        ' display it in the Image control.
        Dim t3 = tiledImage.ContinueWith(Sub(antecedent)
                                             ' Get System DPI.
                                             Dim m As Matrix = PresentationSource.FromVisual(Application.Current.MainWindow).CompositionTarget.TransformToDevice
                                             Dim dpiX As Double = m.M11
                                             Dim dpiY As Double = m.M22

                                             ' Use the default palette in creating the bitmap.
                                             Dim bms As BitmapSource = BitmapSource.Create(largeImagePixelWidth,
                                                                                           largeImagePixelHeight,
                                             dpiX,
                                             dpiY,
                                             format,
                                             palette,
                                             antecedent.Result,
                                             largeImageStride)
                                             image.Source = bms
                                         End Sub, UISyncContext)
    End Sub

    Public Function LoadImage(filename As String) As Byte()
        ' Use the WPF BitmapImage class to load and 
        ' resize the bitmap. NOTE: Only 32bpp formats are supported correctly.
        ' Support for additional color formats Is left as an exercise
        ' for the reader. For more information, see documentation for ColorConvertedBitmap.
        Dim bitmapImage As New BitmapImage()
        bitmapImage.BeginInit()
        bitmapImage.UriSource = New Uri(filename)
        bitmapImage.DecodePixelHeight = tilePixelHeight
        bitmapImage.DecodePixelWidth = tilePixelWidth
        bitmapImage.EndInit()

        format = bitmapImage.Format
        Dim size As Integer = CInt(bitmapImage.Height * bitmapImage.Width)
        Dim stride As Integer = CInt(bitmapImage.Width * 4)
        Dim dest(stride * tilePixelHeight - 1) As Byte

        bitmapImage.CopyPixels(dest, stride, 0)

        Return dest
    End Function

    Function Stride(pixelWidth As Integer, bitsPerPixel As Integer) As Integer
        Return (((pixelWidth * bitsPerPixel + 31) / 32) * 4)
    End Function

    ' Map the individual image tiles to the large image
    ' in parallel. Any kind of raw image manipulation can be
    ' done here because we are Not attempting to access any 
    ' WPF controls from multiple threads.
    Function TileImages(sourceImages As Task(Of Byte())()) As Byte()
        Dim largeImage(largeImagePixelHeight * largeImageStride - 1) As Byte
        Dim tileImageStride As Integer = tilePixelWidth * 4 ' hard coded To 32bpp

        Dim rand As New Random()
        Parallel.For(0, rowCount * colCount, Sub(i)
                                                 ' Pick one of the images at random for this tile.
                                                 Dim cur As Integer = rand.Next(0, sourceImages.Length)
                                                 Dim pixels() As Byte = sourceImages(cur).Result

                                                 ' Get the starting index for this tile.
                                                 Dim row As Integer = i \ colCount
                                                 Dim col As Integer = i Mod colCount
                                                 Dim idx As Integer = ((row * (largeImageStride * tilePixelHeight)) + (col * tileImageStride))

                                                 ' Write the pixels for the current tile. The pixels are Not contiguous
                                                 ' in the array, therefore we have to advance the index by the image stride
                                                 ' (minus the stride of the tile) for each scanline of the tile.
                                                 Dim tileImageIndex As Integer = 0
                                                 For j As Integer = 0 To tilePixelHeight - 1
                                                     ' Write the next scanline for this tile.
                                                     For k As Integer = 0 To tileImageStride - 1
                                                         largeImage(idx) = pixels(tileImageIndex)
                                                         idx += 1
                                                         tileImageIndex += 1
                                                     Next
                                                     ' Advance to the beginning of the next scanline.
                                                     idx += largeImageStride - tileImageStride
                                                 Next
                                             End Sub)
        Return largeImage
    End Function
End Class

Chcete-li vytvořit příklad, vytvořit projekt aplikace WPF v aplikaci Visual Studio a pojmenovat ho WPF_CS1 ( C# pro projekt WPF) nebo WPF_VB1 (pro Visual Basic projekt WPF).To create the example, create a WPF application project in Visual Studio and name it WPF_CS1 (for a C# WPF project) or WPF_VB1 (for a Visual Basic WPF project). Pak udělejte tyto kroky:Then do the following:

  1. V návrhovém zobrazení přetáhněte ovládací prvek Image z panelu nástrojů do levého horního rohu návrhové plochy.In design view, drag an Image control from the Toolbox onto the upper left corner of the design surface. Do textového pole název v okně vlastnosti pojmenujte ovládací prvek "image".In the Name textbox of the Properties window, name the control "image".

  2. Přetáhněte ovládací prvek Button ze sady nástrojů do dolní levé části okna aplikace.Drag a Button control from the Toolbox to the lower left part of the application window. V zobrazení XAML zadejte vlastnost Content tlačítka jako "vytvořit mozaika" a určete jeho vlastnost Width jako "100".In XAML view, specify the Content property of the button as "Make a mosaic", and specify its Width property as "100". Připojte událost Click k obslužné rutině události button_Click definované v kódu příkladu přidáním Click="button_Click" do prvku <Button>.Connect the Click event with the button_Click event handler defined in the example's code by adding Click="button_Click" to the <Button> element. Do textového pole název v okně vlastnosti pojmenujte ovládací prvek "tlačítko".In the Name textbox of the Properties window, name the control "button".

  3. Celý obsah souboru MainWindow.xaml.cs nebo MainWindow. XAML. vb nahraďte kódem z tohoto příkladu.Replace the entire contents of the MainWindow.xaml.cs or MainWindow.xaml.vb file with the code from this example. Pro projekt C# WPF se ujistěte, že název pracovního prostoru odpovídá názvu projektu.For a C# WPF project, make sure that the name of the workspace matches the project name.

  4. Tento příklad načte obrázky JPEG z adresáře s názvem C:\Users\Public\Pictures\Sample obrázky\.The example reads JPEG images from a directory named C:\Users\Public\Pictures\Sample Pictures\. Buď vytvořte adresář a umístěte do něj některé obrázky, nebo změňte cestu tak, aby odkazovala na jiný adresář, který obsahuje obrázky.Either create the directory and place some images in it, or change the path to refer to some other directory that contains images.

Tento příklad má určitá omezení.This example has some limitations. Například jsou podporovány pouze obrázky 32-bitů na pixel. v průběhu operace změny velikosti jsou obrázky v jiných formátech poškozeny objektem BitmapImage.For example, only 32-bits-per-pixel images are supported; images in other formats are corrupted by the BitmapImage object during the resizing operation. Kromě toho musí být zdrojové obrázky větší než velikost dlaždice.Also, the source images must all be larger than the tile size. Jako další cvičení můžete přidat funkce pro zpracování více formátů pixelů a velikostí souborů.As a further exercise, you can add functionality to handle multiple pixel formats and file sizes.

Konstruktory

TaskScheduler()

Inicializuje TaskScheduler.Initializes the TaskScheduler.

Vlastnosti

Current

Získá TaskScheduler přidružený k aktuálně spuštěné úloze.Gets the TaskScheduler associated with the currently executing task.

Default

Získá výchozí instanci TaskScheduler poskytovanou .NET Framework.Gets the default TaskScheduler instance that is provided by the .NET Framework.

Id

Získá jedinečné ID pro tento TaskScheduler.Gets the unique ID for this TaskScheduler.

MaximumConcurrencyLevel

Určuje maximální úroveň souběžnosti, kterou tento TaskScheduler může podporovat.Indicates the maximum concurrency level this TaskScheduler is able to support.

Metody

Equals(Object)

Určuje, zda se zadaný objekt rovná aktuálnímu objektu.Determines whether the specified object is equal to the current object.

(Zděděno od Object)
Finalize()

Uvolní všechny prostředky přidružené k tomuto plánovači.Frees all resources associated with this scheduler.

FromCurrentSynchronizationContext()

Vytvoří TaskScheduler přidružený k aktuálnímu SynchronizationContext.Creates a TaskScheduler associated with the current SynchronizationContext.

GetHashCode()

Slouží jako výchozí funkce hash.Serves as the default hash function.

(Zděděno od Object)
GetScheduledTasks()

Pouze pro podporu ladicího programu vygeneruje výčty Task instance, které jsou aktuálně zařazeny do fronty čekající na provedení.For debugger support only, generates an enumerable of Task instances currently queued to the scheduler waiting to be executed.

GetType()

Získá Type aktuální instance.Gets the Type of the current instance.

(Zděděno od Object)
MemberwiseClone()

Vytvoří kopii aktuálního Objectbez podstruktury.Creates a shallow copy of the current Object.

(Zděděno od Object)
QueueTask(Task)

Zařadí Task do fronty plánovači.Queues a Task to the scheduler.

ToString()

Vrací řetězec, který představuje aktuální objekt.Returns a string that represents the current object.

(Zděděno od Object)
TryDequeue(Task)

Pokusí se Dequeue Task, která byla dříve zařazena do fronty tohoto plánovače.Attempts to dequeue a Task that was previously queued to this scheduler.

TryExecuteTask(Task)

Pokusí se spustit zadaný Task v tomto plánovači.Attempts to execute the provided Task on this scheduler.

TryExecuteTaskInline(Task, Boolean)

Určuje, zda lze poskytnuté Task spustit synchronně v tomto volání, a pokud je může, provede ji.Determines whether the provided Task can be executed synchronously in this call, and if it can, executes it.

Události

UnobservedTaskException

Vyvolá se v případě, že nepozorovaná výjimka úlohy s chybou má aktivovat zásady eskalace výjimek, které ve výchozím nastavení ukončí proces.Occurs when a faulted task's unobserved exception is about to trigger exception escalation policy, which, by default, would terminate the process.

Platí pro

Bezpečný přístup z více vláken

Všechny členy abstraktního typu TaskScheduler jsou bezpečné pro přístup z více vláken a lze je použít z více vláken současně.All members of the abstract TaskScheduler type are thread-safe and may be used from multiple threads concurrently.

Viz také