TaskScheduler Osztály

Definíció

Olyan objektumot jelöl, amely kezeli a sorokba sorba állítási tevékenységek alacsony szintű munkáját a szálakon.

public ref class TaskScheduler abstract
public abstract class TaskScheduler
type TaskScheduler = class
Public MustInherit Class TaskScheduler
Öröklődés
TaskScheduler

Példák

Az alábbi példa létrehoz egy egyéni feladatütemezőt, amely korlátozza az alkalmazás által használt szálak számát. Ezután két tevékenységcsoportot indít el, és megjeleníti a tevékenységre és a tevékenység végrehajtására szolgáló szálra vonatkozó információkat.

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

Megjegyzések

Az TaskScheduler osztály egy feladatütemezőt jelöl. A feladatütemezők biztosítják, hogy egy tevékenység munkája végül végrehajtásra kerül.

Az alapértelmezett feladatütemező munkalopást biztosít a terhelés kiegyensúlyozásához, szálak injektálását és visszavonását a maximális áteresztőképesség érdekében, valamint általánosan jó teljesítményt nyújt. A legtöbb forgatókönyvhöz elegendőnek kell lennie.

Az TaskScheduler osztály az összes testreszabható ütemezési logika bővítménypontjaként is szolgál. Ez olyan mechanizmusokat is magában foglal, mint a tevékenységek ütemezése a végrehajtáshoz, és hogy az ütemezett tevékenységek hogyan legyenek kitéve a hibakeresőknek. Ha speciális funkciókra van szüksége, létrehozhat egy egyéni ütemezőt, és engedélyezheti azt adott feladatokhoz vagy lekérdezésekhez.

Az alapértelmezett feladatütemező és a szálkészlet

A párhuzamos feladattár és a PLINQ alapértelmezett ütemezője az osztály által képviselt .NET-szálkészletet használja a ThreadPool feladatok várólistára helyezéséhez és végrehajtásához. A szálmedence a Task típus által biztosított információkat felhasználja a párhuzamos feladatok és lekérdezések által gyakran megvalósított finoman ágazó párhuzamosság (rövid élettartamú munkaegységek) hatékony támogatására.

A globális üzenetsor és a helyi üzenetsorok

A szálkészlet minden alkalmazási tartományban egy globális FIFO-munkasort (first-in, first-out) tart fenn a szálakhoz. Amikor egy program meghívja a ThreadPool.QueueUserWorkItem (vagy ThreadPool.UnsafeQueueUserWorkItem) metódust, a feladatot egy megosztott várólistára helyezik, és végül levételezik róla a következő szálra, amely elérhetővé válik. A .NET-keretrendszer 4-től kezdve ez az üzenetsor egy, az ConcurrentQueue<T> osztályhoz hasonló zárolásmentes algoritmust használ. Ezzel a zárolásmentes implementációval a szálmedence kevesebb időt tölt a munkaelemek sorba állításakor és eltávolításakor. Ez a teljesítménybeli előny minden olyan program számára elérhető, amely a szálkészletet használja.

A legfelső szintű tevékenységek, amelyek nem egy másik tevékenység kontextusában lettek létrehozva, ugyanúgy kerülnek a globális várólistára, mint bármely más munkaelemre. A beágyazott vagy gyermek feladatokat azonban, amelyek egy másik tevékenység kontextusában jönnek létre, meglehetősen eltérően kezelik. A gyermek- vagy beágyazott feladat egy helyi üzenetsorra kerül, amely kifejezetten annak a szálnak a sajátja, amelyen a szülőfeladat végrehajtódik. A szülőfeladat lehet legfelső szintű feladat, vagy lehet egy másik feladatnak is alfeladata. Ha ez a szál készen áll a további munkára, először a helyi üzenetsorban jelenik meg. Ha a munkaelemek ott várnak, gyorsan elérhetők. A helyi üzenetsorok elérése az utolsó be, első ki sorrendben (LIFO) történik a gyorsítótár helyének megőrzése és a versengés csökkentése érdekében. További információ a gyermekfeladatokról és a beágyazott feladatokról: Csatolt és leválasztott gyermekfeladatok.

A helyi üzenetsorok használata nem csak csökkenti a globális üzenetsorra nehezedő nyomást, hanem kihasználja az adat helyének előnyeit is. A helyi üzenetsor munkaelemei gyakran hivatkoznak olyan adatstruktúrákra, amelyek fizikailag közel vannak egymáshoz a memóriában. Ezekben az esetekben az adatok már az első feladat futtatása után a gyorsítótárban vannak, és gyorsan elérhetők. A párhuzamos LINQ (PLINQ) és az Parallel osztály egyaránt széles körben használ beágyazott és gyermekfeladatokat, és a helyi munkasorok használatával jelentős gyorsításokat érhet el.

Munkalopás

A .NET-keretrendszer 4-től kezdve a szálkészlet egy munkalopó algoritmust is tartalmaz, amely segít biztosítani, hogy a szálak ne legyenek tétlenek, míg másoknak még van munkájuk a feladatsorokban. Ha egy szálkészletbeli szál készen áll a további munkára, először a helyi várakozási sor fejére, majd a globális várakozási sorra, végül a többi szál helyi várakozási soraira néz. Ha egy munkaelemet egy másik szál helyi üzenetsorában talál, először heurisztikus elemeket alkalmaz annak érdekében, hogy hatékonyan tudja futtatni a munkát. Amennyiben lehetséges, az elemet a sor végéről FIFO szerinti sorrendben veszi le. Ez csökkenti az egyes helyi sorokon való versengést, és megőrzi az adatlokalitást. Ez az architektúra segít a szálkészlet terheléselosztásának hatékonyabb működésében, mint a korábbi verziókban.

Hosszan futó feladatok

Előfordulhat, hogy kifejezetten meg szeretné akadályozni, hogy egy feladat helyi sorba kerüljön. Előfordulhat például, hogy egy adott munkaelem viszonylag hosszú ideig fog futni, és valószínűleg blokkolja a helyi üzenetsor összes többi munkaelemét. Ebben az esetben megadhatja a System.Threading.Tasks.TaskCreationOptions beállítást, amely arra utal az ütemező számára, hogy a tevékenységhez további szálra lehet szükség, hogy az ne blokkolja a többi szál vagy munkaelem előrehaladtát a helyi üzenetsoron. Ezzel a beállítással teljesen elkerülheti a szálkészletet, beleértve a globális és a helyi üzenetsorokat is.

Tevékenységbesorolás

Bizonyos esetekben, amikor egy Task-ra várakoznak, előfordulhat, hogy szinkron módon hajtja végre a várakozási műveletet végrehajtó szálon. Ez növeli a teljesítményt azáltal, hogy megakadályozza egy további szál szükségességét, és ehelyett használja a meglévő szálat, amely egyébként blokkolva lett volna. Annak érdekében, hogy elkerüljük a reentrancia okozta hibákat, a feladat beágyazása csak akkor történik meg, ha a várakozási cél megtalálható az adott szál helyi várakozási sorában.

Szinkronizálási környezet megadása

Ezzel a TaskScheduler.FromCurrentSynchronizationContext módszerrel megadhatja, hogy egy tevékenységet ütemezni kell egy adott szálon való futtatásra. Ez olyan keretrendszerekben hasznos, mint a Windows Forms és a Windows megjelenítési alaprendszer, ahol a felhasználói felület objektumaihoz való hozzáférés gyakran arra a kódra korlátozódik, amely ugyanazon a szálon fut, amelyen a felhasználói felületi objektum létre lett hozva.

Az alábbi példa a TaskScheduler.FromCurrentSynchronizationContext Windows megjelenítési alaprendszer (WPF) alkalmazás metódusával ütemez egy feladatot ugyanazon a szálon, amelyen a felhasználói felület vezérlője létre lett hozva. A példa egy mozaikképet hoz létre, amely véletlenszerűen van kiválasztva egy adott könyvtárból. A WPF-objektumok a képek betöltésére és átméretezésére szolgálnak. A nyers képpontokat ezután egy feladatnak adják át, amely hurkot For használ a képpontadatok egybájtos nagy tömbbe való írásához. Nincs szükség szinkronizálásra, mert két csempe sem foglalja el ugyanazokat a tömbelemeket. A csempék bármilyen sorrendben megírhatók, mert a pozíciójuk a többi csempétől függetlenül számítható ki. A nagyméretű tömb ezután egy felhasználói felületen futó feladatnak lesz átadva, ahol a képpontadatok betöltődnek egy képvezérlőbe.

A példa áthelyezi az adatokat a felhasználói felületi szálról, párhuzamos hurkok és Task objektumok használatával módosítja őket, majd átadja azokat egy, a felhasználói felületen futó feladatnak. Ez a megközelítés akkor hasznos, ha a feladat párhuzamos kódtárával olyan műveleteket kell végrehajtania, amelyeket a WPF API nem támogat, vagy nem elég gyorsak. Képmozaik létrehozásának másik módja a WPF-ben egy vezérlő használata System.Windows.Controls.WrapPanel és képek hozzáadása. A WrapPanel végzi a csempék elhelyezésének munkáját. Ez a munka azonban csak a felhasználói felületen végezhető el.

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;
        }
    }
}

A példa létrehozásához hozzon létre egy WPF-alkalmazásprojektet a Visual Studióban, és nevezze el WPF_CS1 (C# WPF-projekt esetén) vagy WPF_VB1 (Visual Basic WPF-projekt esetén). Ezután tegye a következőket:

  1. Tervező nézetben húzzon egy vezérlőt Image az Eszközkészletből a tervezőfelület bal felső sarkába. A Tulajdonságok ablak Név szövegmezőjében adja meg a vezérlő "képének" nevét.

  2. Húzza a vezérlőt Button az eszközkészletből az alkalmazás ablakának bal alsó részére. XAML nézetben adja meg a Content gomb tulajdonságát "Mozaik készítése" értékként, és adja meg a tulajdonságát Width "100" értékként. Kösse össze a Click eseményt a button_Click eseménykezelővel, amely a példa kódjában van definiálva, azzal, hogy hozzáadja Click="button_Click" az <Button> elemhez. A Tulajdonságok ablak Név szövegmezőjében adja meg a vezérlő "gombját".

  3. Cserélje le a MainWindow.xaml.cs vagy MainWindow.xaml.vb fájl teljes tartalmát a példában szereplő kódra. C# WPF-projekt esetén győződjön meg arról, hogy a munkaterület neve megegyezik a projekt nevével.

  4. A példa JPEG-képeket olvas be egy C:\Users\Public\Pictures\Sample Pictures nevű könyvtárból. Hozza létre a könyvtárat, és helyezzen bele néhány képet, vagy módosítsa az elérési utat, hogy más, képeket tartalmazó könyvtárra hivatkozzon.

Ez a példa bizonyos korlátozásokkal rendelkezik. Például csak a 32 bites-per-képpontos képek vannak támogatva; más formátumú képeket az BitmapImage objektum átméretezéskor sért meg. Emellett a forrásképek mindegyikének mérete nagyobbnak kell lennie, mint a csempe mérete. További gyakorlatként hozzáadhatsz funkciókat, amelyek többféle képpontformátumot és fájlméretet is képesek kezelni.

Konstruktorok

Name Description
TaskScheduler()

Inicializálja a TaskScheduler.

Tulajdonságok

Name Description
Current

Lekéri az TaskScheduler aktuálisan végrehajtó feladathoz társítottat.

Default

Lekéri a .NET által biztosított alapértelmezett TaskScheduler példányt.

Id

Lekéri ennek az egyedi azonosítónak a TaskSchedulerazonosítóját.

MaximumConcurrencyLevel

Azt a maximális egyidejűségi szintet jelzi, amelyet TaskScheduler ez támogatni tud.

Metódusok

Name Description
Equals(Object)

Meghatározza, hogy a megadott objektum egyenlő-e az aktuális objektummal.

(Öröklődés forrása Object)
Finalize()

Felszabadítja az ütemezőhöz társított összes erőforrást.

FromCurrentSynchronizationContext()

Létrehoz egy TaskScheduler , az aktuálishoz SynchronizationContexttársítottat.

GetHashCode()

Ez az alapértelmezett kivonatoló függvény.

(Öröklődés forrása Object)
GetScheduledTasks()

Csak hibakeresők támogatása esetén a végrehajtásra váró ütemezőnek jelenleg várólistára helyezett példányok száma enumerálható Task .

GetType()

Lekéri az Type aktuális példányt.

(Öröklődés forrása Object)
MemberwiseClone()

Az aktuális Objectpéldány sekély másolatát hozza létre.

(Öröklődés forrása Object)
QueueTask(Task)

Üzenetsort Task ad az ütemezőnek.

ToString()

Az aktuális objektumot jelképező sztringet ad vissza.

(Öröklődés forrása Object)
TryDequeue(Task)

Megkísérel lekérdezni egy Task korábban az ütemezőhöz várólistára helyezett elemeket.

TryExecuteTask(Task)

Megkísérli végrehajtani a megadott Task műveletet ezen az ütemezőn.

TryExecuteTaskInline(Task, Boolean)

Meghatározza, hogy a megadott Task hívás szinkron módon végrehajtható-e ebben a hívásban, és ha lehet, végrehajtja-e.

esemény

Name Description
UnobservedTaskException

Akkor fordul elő, ha egy hibás tevékenység nem figyelt kivétele a kivétel eszkalálási szabályzatának aktiválására készül, amely alapértelmezés szerint leállítja a folyamatot.

A következőre érvényes:

Szálbiztonság

Az absztrakt TaskScheduler típus minden tagja szálbiztos, és egyszerre több szálból is használható.

Lásd még