Na metodama Task.Factory.StartNew i Task.Run

Kada kreirate zadatke pomoću metoda Task.Factory.StartNew ili Task.Run, trebali biste imati na umu određene važne točke prilikom pisanja asinkronog koda. U većini slučajeva poželjno je izbjegavati upotrebu metode Task.Factory.StartNew ako radite s asinkronim kodom. Ako radite s paralelnim kodom, rekao bih da je StartNew dobar izbor.

Planer zadataka komponenta je koja je odgovorna za raspoređivanje zadataka; Okvir .Net nudi vam dva planera zadataka. Postoji zadani planer zadataka koji se izvodi na spremištu niti .Net framework, a postoji i planer zadataka koji se izvršava u kontekstu sinkronizacije određenog cilja. Zadani planer zadataka bit će dovoljan većinu vremena, ali također možete izraditi vlastiti prilagođeni planer zadataka kako biste pružili dodatne funkcije. Da biste izradili vlastiti prilagođeni planer zadataka, trebali biste stvoriti klasu koja proširuje klasu System.Threading.Tasks.TaskScheduler.

Kako mogu stvoriti zadatke pomoću knjižnice paralelnih zadataka?

Postoji nekoliko načina na koje možete stvoriti i pokrenuti zadatke u .Netu. Morate koristiti klasu System.Threading.Tasks.Task ili System.Threading.Tasks.Task da biste stvorili zadatke (jedinica rada koja se može planirati). Dok se prvi koristi za stvaranje zadatka koji ne vraća vrijednost, drugi se koristi za stvaranje zadataka koji imaju povratne vrijednosti. Svojstvo Task.Factory je instanca klase TaskFactory. Ovo se svojstvo koristi za stvaranje i raspoređivanje zadataka. Iako metoda Task.Factory.StartNew djeluje poput operacije račvanja i koristi se za stvaranje i pokretanje novih zadataka, metoda Wait djeluje poput operacije spajanja i čeka da zadatak bude dovršen.

Sljedeći isječak koda ilustrira kako možete koristiti metodu Task.Factory.StartNew.

Task.Factory.StartNew(() => TestMethod(), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);

Zadatak možete stvoriti i pomoću metode Task.Run, kao što je prikazano u isječku koda u nastavku.

public async Task DoSomeWork()

        {

            await Task.Run(() => TestMethod());

        }

        void TestMethod()

        {

            Console.WriteLine("Hello world!");

        }

Ako želite vratiti vrijednost iz zadatka, možete iskoristiti metodu Task.FromResult kako je prikazano u isječku koda u nastavku.

public async Task DoSomeWork()

   {

      string text = await Task.FromResult(GetMessage());

   }

private string GetMessage()

   {

      return "Hello world!";

   }

Također možete stvoriti zadatke pomoću delegata ili akcije. Sljedeći isječak koda pokazuje kako možete stvoriti zadatke pomoću akcija i delegata.

Task task1 = new Task (new Action(Display));

task1.Start();

Task task2 = new Task (delegate { Display(); });

task2.Start();

Također možete kreirati zadatke pomoću lamba i anonimnih metoda.

Task.Factory.StartNew i Task.Run

Task.Factory.StartNew je brz način stvaranja i pokretanja zadatka. Imajte na umu da je poziv Task.Factory.StartNew funkcionalno ekvivalentan stvaranju instance zadatka, a zatim pozivanju metode Start na instanci. Međutim, ne preporučuje se korištenje iz obilnih razloga. Ako želite izvršiti sinkroni kod, Task.Factory.StartNew nije dobar izbor.

Imajte na umu da će, ako je dostupan raspoređivač zadataka, metoda StartNew izvršiti zadatak na tom planeru zadataka. Naprotiv, ako planer nije dostupan, izvršit će zadatak na niti spremišta niti. Treba napomenuti da Task.Factory.StartNew po defaultu zadaje TaskScheduler.Current, a ne TaskScheduler.Default.

Imajte na umu da je poziv Task.Run (akcija) ekvivalentan sljedećoj izjavi: Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

Naprotiv, poziv Task.Factory.StartNew (akcija) ekvivalentan je sljedećoj izjavi:

Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current);

Ako možda želite koristiti Task.Factory.StartNew ako ste kreirali prilagođeni planer zadataka i eksplicitno mu proslijedili instancu planera. Uvijek bih preporučio upotrebu Task.Run-a jer je puno jednostavniji i ima sigurnije zadane postavke. Drugim riječima, trebali bismo izbjegavati upotrebu Task.Factory.StartNew, osim ako postoji potreba za izradom planera zadataka, a zatim ga eksplicitno proslijediti prilikom pozivanja metode StartNew za stvaranje novog zadatka i njegovo zakazivanje. Ako biste metodu TaskFactory.StartNew koristili učinkovito i pouzdano, trebali biste koristiti prilagođeni planer zadataka, a zatim odrediti CancellationToken i TaskCreationOptions.

Metodu Task.Run preporučuje se koristiti kada ne trebate imati puno sitnozrnate kontrole nad raspoređivanjem niti i njegovim zamršenostima. Trebali biste koristiti Task.Run prvenstveno na metodama vezanim za CPU. Međutim, trebali biste koristiti Task.Run dok pozivate zadatak, a ne unutar implementacije zadatka. Drugim riječima, trebali biste koristiti Task.Run ne unutar bilo koje implementacije metode već na mjestu na kojem je metoda pozvana. Kao primjer, sljedeći isječak koda primjer je "lošeg" dijela koda.

public async Task DownloadDataFromWebAsync(Uri uri)

        {

            return await Task.Run(() =>

            {

                using (WebClient webClient = new WebClient())

                {

                    return webClient.DownloadString(uri);

                }

            });

        }

Pogledajte gore navedeni isječak koda. Metoda nije skalabilna jer bi blokirala pozadinsku nit, dohvatila nit iz spremišta niti i izvršila je sinkrono na njoj. Stoga bi potrošilo više resursa u vašem sustavu.