Jak zbudować własny harmonogram zadań w C #

TPL (Task Parallel Library) to jedna z najciekawszych nowych funkcji w najnowszych wersjach .NET framework, wprowadzona po raz pierwszy w .NET Framework 4.0. Aby pracować z TPL, musisz skorzystać z przestrzeni nazw System.Threading.Tasks.

Co to są harmonogramy zadań? Dlaczego ich potrzebujemy?

Jak to jest, że zadania są zaplanowane? Cóż, istnieje komponent zwany harmonogramem zadań, który jest odpowiedzialny za planowanie zadań. W istocie jest to abstrakcja dla obiektu niskiego poziomu, który może kolejkować twoje zadania do wątków.

NET Framework udostępnia dwa programy do planowania zadań. Obejmują one domyślny harmonogram zadań, który działa w puli wątków platformy .NET Framework, oraz inny harmonogram zadań, który jest wykonywany w kontekście synchronizacji określonego celu. Należy zauważyć, że domyślny harmonogram zadań TPL korzysta z puli wątków platformy .NET Framework. Ta pula wątków jest z kolei reprezentowana przez klasę ThreadPool zawartą w przestrzeni nazw System.Threading.Tasks.

Chociaż domyślny harmonogram zadań będzie wystarczający przez większość czasu, możesz chcieć zbudować własny niestandardowy harmonogram zadań, aby zapewnić dodatkowe funkcje, tj. Funkcje, które nie są dostarczane przez domyślny harmonogram zadań. Takie funkcje mogą obejmować wykonanie FIFO, stopień współbieżności itp.

Rozszerz klasę TaskScheduler w C #

Aby zbudować własny, niestandardowy harmonogram zadań, należałoby utworzyć klasę rozszerzającą klasę System.Threading.Tasks.TaskScheduler. Aby więc zbudować niestandardowy harmonogram zadań, należałoby rozszerzyć klasę abstrakcyjną TaskScheduler i zastąpić następujące metody.

  • QueueTask zwraca void i akceptuje obiekt Task jako parametr, a ta metoda jest wywoływana, gdy zadanie ma zostać zaplanowane
  • GetScheduledTasks zwraca listę (dokładniej IEnumerable) wszystkich zadań, które zostały zaplanowane
  • TryExecuteTaskInline służy do wykonywania zadań w tekście, czyli w bieżącym wątku. W tym przypadku zadania są wykonywane bez konieczności ich kolejkowania

Poniższy fragment kodu pokazuje, jak można rozszerzyć klasę TaskScheduler, aby zaimplementować niestandardowy harmonogram w języku C #.

public class CustomTaskScheduler: TaskScheduler, IDisposable

    {

    }

Jak omówiliśmy wcześniej w tym artykule, należy zastąpić metody GetScheduledTasks, QueueTask i TryExecuteTaskInline w niestandardowym harmonogramie zadań.

publicznie zapieczętowana klasa CustomTaskScheduler: TaskScheduler, IDisposable

  {

        chronione przesłonięcie IEnumerable GetScheduledTasks ()

        {

            //DO ZROBIENIA

        }

        protected override void QueueTask (zadanie zadania)

        {

             //DO ZROBIENIA

        }

        protected override bool TryExecuteTaskInline (zadanie zadania, zadanie boolWasPreviouslyQueued)

        {

            //DO ZROBIENIA

        }

        public void Dispose ()

        {

            //DO ZROBIENIA

        }

  }

Użyj BlockingCollection do przechowywania kolekcji obiektów zadań w C #

Zacznijmy teraz wdrażać nasz niestandardowy harmonogram zadań. Poniższy fragment kodu pokazuje, jak można wykorzystać BlockingCollection do przechowywania kolekcji obiektów zadań.

publicznie zapieczętowana klasa CustomTaskScheduler: TaskScheduler, IDisposable

 {

        private BlockingCollection taskCollection = new BlockingCollection ();

        prywatny tylko do odczytu Wątek mainThread = null;

        public CustomTaskScheduler ()

        {

            mainThread = nowy wątek (nowy ThreadStart (Wykonaj));

            if (! mainThread.IsAlive)

            {

                mainThread.Start ();

            }

        }

        private void Execute ()

        {

            foreach (zadanie var w taskCollection.GetConsumingEnumerable ())

            {

                TryExecuteTask (zadanie);

            }

        } 

      //Inne metody

  }

Zapoznaj się z konstruktorem klasy CustomTaskScheduler. Zwróć uwagę, jak utworzono nowy wątek i uruchomiono metodę Execute.

Zaimplementuj metody GetScheduledTasks, QueueTask i TryExecuteTaskInline w języku C #

Następnie musimy zaimplementować trzy metody, które musimy przesłonić w naszym niestandardowym harmonogramie zadań. Te trzy metody obejmują GetScheduledTasks, QueueTask i TryExecuteTaskInline.

Metoda GetScheduledTasks zwraca wystąpienie kolekcji zadań jako IEnumerable. Jest to używane, aby można było wyliczyć kolekcję, jak pokazano w metodzie Execute. Metoda QueueTask akceptuje obiekt Task jako parametr i przechowuje go w kolekcji zadań. Metoda TryExecuteTaskInline nie ma implementacji - pozostawię to czytelnikowi, aby ją zaimplementował.

chronione przesłonięcie IEnumerable GetScheduledTasks ()

        {

            return taskCollection.ToArray ();

        }

        protected override void QueueTask (zadanie zadania)

        {

            if (zadanie! = null)

                taskCollection.Add (zadanie);

        }

        protected override bool TryExecuteTaskInline (zadanie zadania, zadanie boolWasPreviouslyQueued)

        {

            return false;

        }

Kompletny przykład CustomTaskScheduler w języku C #

Poniższa lista kodu ilustruje ostateczną wersję naszego CustomTaskScheduler.

publicznie zapieczętowana klasa CustomTaskScheduler: TaskScheduler, IDisposable

    {

        private BlockingCollection taskCollection = new BlockingCollection ();

        prywatny tylko do odczytu Wątek mainThread = null;

        public CustomTaskScheduler ()

        {

            mainThread = nowy wątek (nowy ThreadStart (Wykonaj));

            if (! mainThread.IsAlive)

            {

                mainThread.Start ();

            }

        }

        private void Execute ()

        {

            foreach (zadanie var w taskCollection.GetConsumingEnumerable ())

            {

                TryExecuteTask (zadanie);

            }

        }

        chronione przesłonięcie IEnumerable GetScheduledTasks ()

        {

            return taskCollection.ToArray ();

        }

        protected override void QueueTask (zadanie zadania)

        {

            if (zadanie! = null)

                taskCollection.Add (zadanie);           

        }

        protected override bool TryExecuteTaskInline (zadanie zadania, zadanie boolWasPreviouslyQueued)

        {

            return false;

        }

        private void Dispose (bool disposing)

        {

            if (! disposing) return;

            taskCollection.CompleteAdding ();

            taskCollection.Dispose ();

        }

        public void Dispose ()

        {

            Dispose (prawda);

            GC.SuppressFinalize (this);

        }

    }

Aby skorzystać z niestandardowego harmonogramu zadań, który właśnie zaimplementowaliśmy, możesz użyć następującego fragmentu kodu:

CustomTaskScheduler taskScheduler = new CustomTaskScheduler ();

Task.Factory.StartNew (() => SomeMethod (), CancellationToken.None, TaskCreationOptions.None, taskScheduler);

Jak zrobić więcej w C #:

  • Kiedy używać klasy abstrakcyjnej, a kiedy interfejsu w języku C #
  • Jak pracować z AutoMapper w C #
  • Jak używać wyrażeń lambda w C #
  • Jak pracować z delegatami Action, Func i Predicate w C #
  • Jak pracować z delegatami w C #
  • Jak zaimplementować prosty rejestrator w C #
  • Jak pracować z atrybutami w C #
  • Jak pracować z log4net w C #
  • Jak zaimplementować wzorzec projektu repozytorium w C #
  • Jak pracować z odbiciem w C #
  • Jak pracować z Filesystemwatcher w C #
  • Jak wykonać leniwą inicjalizację w C #
  • Jak pracować z MSM w C #
  • Jak pracować z metodami rozszerzającymi w C #
  • Jak nam wyrażenia lambda w C #
  • Kiedy używać słowa kluczowego volatile w języku C #
  • Jak używać słowa kluczowego yield w języku C #
  • Jak zaimplementować polimorfizm w C #
  • Jak zbudować własny harmonogram zadań w C #
  • Jak pracować z RabbitM w C #
  • Jak pracować z krotką w C #
  • Eksplorowanie metod wirtualnych i abstrakcyjnych w C #