TaskScheduler Klas

Definitie

Vertegenwoordigt een object dat het werk op laag niveau afhandelt van wachtrijtaken op threads.

public ref class TaskScheduler abstract
public abstract class TaskScheduler
type TaskScheduler = class
Public MustInherit Class TaskScheduler
Overname
TaskScheduler

Voorbeelden

In het volgende voorbeeld wordt een aangepaste taakplanner gemaakt waarmee het aantal threads dat door de app wordt gebruikt, wordt beperkt. Vervolgens worden twee sets taken gestart en wordt informatie weergegeven over de taak en de thread waarop de taak wordt uitgevoerd.

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

Opmerkingen

De TaskScheduler klasse vertegenwoordigt een taakplanner. Een taakplanner zorgt ervoor dat het werk van een taak uiteindelijk wordt uitgevoerd.

De standaardtaakplanner biedt werkstelen voor taakverdeling, threadinjectie/verwijdering voor maximale doorvoer, en goede algehele prestaties. Dit moet voldoende zijn voor de meeste scenario's.

De TaskScheduler klasse fungeert ook als uitbreidingspunt voor alle aanpasbare planningslogica. Dit omvat mechanismen zoals het plannen van een taak voor uitvoering en hoe geplande taken moeten worden blootgesteld aan foutopsporingsprogramma's. Als u speciale functionaliteit nodig hebt, kunt u een aangepaste planner maken en deze inschakelen voor specifieke taken of query's.

De standaardtaakplanner en de threadgroep

De standaardplanner voor de Taakparallelbibliotheek en PLINQ maakt gebruik van de .NET threadpool, die wordt vertegenwoordigd door de ThreadPool klasse, om werk in de wachtrij te plaatsen en uit te voeren. De threadpool gebruikt de informatie die door het Task type wordt verstrekt om efficiënt ondersteuning te verlenen voor het fijnmazige parallelisme (kortdurende werkeenheden) die parallelle taken en query's vaak vertegenwoordigen.

De globale wachtrij versus lokale wachtrijen

De threadpool onderhoudt een globale FIFO-wachtrij (first-in, first-out) voor threads in elk toepassingsdomein. Wanneer een programma de ThreadPool.QueueUserWorkItem (of ThreadPool.UnsafeQueueUserWorkItem) methode aanroept, wordt het werk in deze gedeelde wachtrij geplaatst en uiteindelijk uit de wachtrij gehaald en toegewezen aan de volgende thread die beschikbaar komt. Vanaf .NET Framework 4 maakt deze wachtrij gebruik van een vergrendelingsvrij algoritme dat lijkt op de ConcurrentQueue<T> klasse. Door deze implementatie zonder vergrendeling te gebruiken, besteedt de threadpool minder tijd aan het in- en uit de wachtrij halen van werkitems. Dit prestatievoordeel is beschikbaar voor alle programma's die gebruikmaken van de threadgroep.

Taken op het hoogste niveau, taken die niet in de context van een andere taak worden gemaakt, worden net als elk ander werkitem in de globale wachtrij geplaatst. Geneste of onderliggende taken, die in de context van een andere taak worden gemaakt, worden echter heel anders verwerkt. Een kind- of geneste taak wordt in een lokale wachtrij geplaatst die specifiek is voor de thread waarop de bovenliggende taak wordt uitgevoerd. De bovenliggende taak kan een taak op het hoogste niveau zijn of ook een subtaak van een andere taak. Wanneer deze thread klaar is voor meer werk, wordt deze eerst in de lokale wachtrij weergegeven. Als werkitems daar wachten, kunnen ze snel worden geopend. De lokale wachtrijen worden in de last-in, first-out volgorde (LIFO) toegepast om de lokaliteit van de cache te behouden en conflicten te verminderen. Zie Gekoppelde en losgekoppelde onderliggende taken voor meer informatie over kind-taken en geneste taken.

Het gebruik van lokale wachtrijen vermindert niet alleen de druk op de globale wachtrij, maar maakt ook gebruik van gegevenslocatie. Werkitems in de lokale wachtrij verwijzen vaak naar gegevensstructuren die zich fysiek in het geheugen bevinden. In deze gevallen bevinden de gegevens zich al in de cache nadat de eerste taak is uitgevoerd en kunnen ze snel worden geopend. Zowel Parallel LINQ (PLINQ) als de Parallel klasse maken uitgebreid gebruik van geneste taken en kindtaken en bereiken aanzienlijke snelheidsverhogingen met behulp van de lokale werkwachtrijen.

Taak stelen

Vanaf .NET Framework 4 beschikt de threadpool ook over een werkafschermingsalgoritme om ervoor te zorgen dat er geen threads inactief zijn terwijl anderen nog steeds werk in hun wachtrijen hebben. Wanneer een thread-pool-thread klaar is voor meer werk, kijkt het eerst naar het hoofd van zijn lokale wachtrij, vervolgens in de globale wachtrij en daarna in de lokale wachtrijen van andere threads. Als er een werkitem wordt gevonden in de lokale wachtrij van een andere thread, past het eerst heuristiek toe om ervoor te zorgen dat het werk efficiënt kan worden uitgevoerd. Als dat mogelijk is, wordt het werkitem uit de staart verwijderd (in FIFO-volgorde). Dit vermindert conflicten in elke lokale wachtrij en behoudt de locatie van gegevens. Deze architectuur helpt de load balancer van de threadpool efficiënter te werken dan in eerdere versies.

Langlopende taken

Mogelijk wilt u expliciet voorkomen dat een taak in een lokale wachtrij wordt geplaatst. U weet bijvoorbeeld dat een bepaald werkitem relatief lang wordt uitgevoerd en waarschijnlijk alle andere werkitems in de lokale wachtrij blokkeert. In dit geval kunt u de System.Threading.Tasks.TaskCreationOptions optie opgeven, die een hint biedt aan de planner dat een extra thread mogelijk vereist is voor de taak, zodat de voortgang van andere threads of werkitems in de lokale wachtrij niet wordt geblokkeerd. Door deze optie te gebruiken, vermijdt u de threadpool volledig, inclusief de globale en lokale wachtrijen.

Taak inlining

In sommige gevallen wanneer er op een Task wordt gewacht, kan deze misschien synchroon worden uitgevoerd op de thread die de wachtbewerking uitvoert. Dit verbetert de prestaties door de noodzaak van een extra thread te voorkomen en in plaats daarvan de bestaande thread te gebruiken, die anders zou zijn geblokkeerd. Om fouten als gevolg van reentrancy te voorkomen, vindt taak-inlining alleen plaats wanneer het wachttarget in de lokale wachtrij van de relevante thread wordt gevonden.

Een synchronisatiecontext opgeven

U kunt de TaskScheduler.FromCurrentSynchronizationContext methode gebruiken om op te geven dat een taak moet worden gepland voor uitvoering op een bepaalde thread. Dit is handig in frameworks zoals Windows Forms en Windows Presentation Foundation, waarbij de toegang tot objecten van de gebruikersinterface vaak wordt beperkt tot code die wordt uitgevoerd op dezelfde thread waarop het UI-object is gemaakt.

In het volgende voorbeeld wordt de TaskScheduler.FromCurrentSynchronizationContext-methode gebruikt in een WPF-app (Windows Presentation Foundation) om een taak te plannen op dezelfde thread waarop het gebruikersinterfacebesturingselement (UI) is gemaakt. In het voorbeeld wordt een mozaïek gemaakt van afbeeldingen die willekeurig zijn geselecteerd uit een opgegeven map. De WPF-objecten worden gebruikt om de afbeeldingen te laden en het formaat ervan te wijzigen. De onbewerkte pixels worden vervolgens doorgegeven aan een taak die gebruikmaakt van een For lus om de pixelgegevens naar een grote matrix met één byte te schrijven. Er is geen synchronisatie vereist omdat er geen twee tegels dezelfde matrixelementen in beslag nemen. De tegels kunnen ook in elke volgorde worden geschreven omdat hun positie onafhankelijk van een andere tegel wordt berekend. De grote array wordt vervolgens doorgegeven aan een taak die wordt uitgevoerd op de gebruikersinterface-thread, waarbij de pixelgegevens worden geladen in een Afbeelding-besturingselement.

Het voorbeeld verplaatst gegevens van de UI-thread, wijzigt deze met behulp van parallelle lussen en Task objecten en geeft deze vervolgens weer door aan een taak die wordt uitgevoerd op de UI-thread. Deze methode is handig wanneer u de taakparallelbibliotheek moet gebruiken om bewerkingen uit te voeren die niet worden ondersteund door de WPF-API of niet snel genoeg zijn. Een andere manier om een afbeeldingsmozaïek in WPF te maken, is door een System.Windows.Controls.WrapPanel besturingselement te gebruiken en er afbeeldingen aan toe te voegen. Het WrapPanel behandelt het werk van de positionering van de tegels. Dit werk kan echter alleen worden uitgevoerd op de 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;
        }
    }
}

Als u het voorbeeld wilt maken, maakt u een WPF-toepassingsproject in Visual Studio en noemt u dit WPF_CS1 (voor een C# WPF-project) of WPF_VB1 (voor een Visual Basic WPF-project). Ga daarna als volgt te werk:

  1. Sleep in de ontwerpweergave een Image besturingselement van de Werkset naar de linkerbovenhoek van het ontwerpoppervlak. Geef in het tekstvak Naam van het venster Eigenschappen de naam van het besturingselement 'afbeelding'.

  2. Sleep een Button controle van de Gereedschapskist naar de linkeronderhoek van het toepassingsvenster. Geef in de XAML-weergave de Content eigenschap van de knop op als 'Een mozaïek maken' en geef Width de eigenschap op als '100'. Verbind de Click gebeurtenis met de button_Click event-handler die is gedefinieerd in de code van het voorbeeld, door Click="button_Click" toe te voegen aan het <Button> element. Geef in het tekstvak Naam van het venster Eigenschappen de naam van het besturingselement 'knop'.

  3. Vervang de volledige inhoud van het MainWindow.xaml.cs- of MainWindow.xaml.vb-bestand door de code uit dit voorbeeld. Zorg ervoor dat de naam van de werkruimte overeenkomt met de projectnaam voor een C# WPF-project.

  4. In het voorbeeld worden JPEG-afbeeldingen gelezen uit een map met de naam C:\Users\Public\Pictures\Sample Pictures. Maak de map en plaats er enkele afbeeldingen in, of wijzig het pad om te verwijzen naar een andere map die afbeeldingen bevat.

In dit voorbeeld gelden enkele beperkingen. Er worden bijvoorbeeld slechts 32-bits-afbeeldingen per pixel ondersteund; afbeeldingen in andere indelingen worden beschadigd door het BitmapImage-object tijdens de bewerking voor het wijzigen van het formaat. De bronafbeeldingen moeten ook allemaal groter zijn dan de tegelgrootte. Als verdere oefening kunt u functionaliteit toevoegen om meerdere pixelindelingen en bestandsgrootten te verwerken.

Constructors

Name Description
TaskScheduler()

Initialiseert de TaskScheduler.

Eigenschappen

Name Description
Current

Hiermee haalt u de TaskScheduler gekoppelde aan de momenteel uitgevoerde taak op.

Default

Hiermee haalt u de standaard-TaskScheduler-instantie op die wordt geleverd door .NET.

Id

Hiermee haalt u de unieke id voor dit TaskSchedulerop.

MaximumConcurrencyLevel

Geeft het maximale gelijktijdigheidsniveau aan dat kan TaskScheduler worden ondersteund.

Methoden

Name Description
Equals(Object)

Bepaalt of het opgegeven object gelijk is aan het huidige object.

(Overgenomen van Object)
Finalize()

Hiermee worden alle resources die aan deze planner zijn gekoppeld, vrijgemaakt.

FromCurrentSynchronizationContext()

Hiermee maakt u een TaskScheduler gekoppeld aan de huidige SynchronizationContext.

GetHashCode()

Fungeert als de standaardhashfunctie.

(Overgenomen van Object)
GetScheduledTasks()

Alleen voor foutopsporingsprogramma-ondersteuning genereert u een opsomming van Task exemplaren die momenteel in de wachtrij staan voor de planner die moet worden uitgevoerd.

GetType()

Hiermee haalt u de Type huidige instantie op.

(Overgenomen van Object)
MemberwiseClone()

Hiermee maakt u een ondiepe kopie van de huidige Object.

(Overgenomen van Object)
QueueTask(Task)

Hiermee wordt een Task wachtrij naar de planner geplaatst.

ToString()

Retourneert een tekenreeks die het huidige object vertegenwoordigt.

(Overgenomen van Object)
TryDequeue(Task)

Hiermee wordt geprobeerd een Task wachtrij op te geven die eerder in de wachtrij was geplaatst voor deze planner.

TryExecuteTask(Task)

Hiermee wordt geprobeerd de opgegeven Task scheduler uit te voeren.

TryExecuteTaskInline(Task, Boolean)

Bepaalt of de opgegeven Task synchroon kan worden uitgevoerd in deze aanroep en of dit wel kan, wordt deze uitgevoerd.

gebeurtenis

Name Description
UnobservedTaskException

Treedt op wanneer een foutieve uitzondering van een taak op het punt staat om escalatiebeleid voor uitzonderingen te activeren. Dit proces wordt standaard beëindigd.

Van toepassing op

Veiligheid thread

Alle leden van het abstracte TaskScheduler type zijn thread-veilig en kunnen gelijktijdig worden gebruikt vanuit meerdere threads.

Zie ook