Odnośnie użycia Task.Start (), Task.Run () i Task.Factory.StartNew ()

143

Właśnie zobaczyłem 3 procedury dotyczące korzystania z TPL, które wykonują tę samą pracę; oto kod:

public static void Main()
{
    Thread.CurrentThread.Name = "Main";

    // Create a task and supply a user delegate by using a lambda expression. 
    Task taskA = new Task( () => Console.WriteLine("Hello from taskA."));
    // Start the task.
    taskA.Start();

    // Output a message from the calling thread.
    Console.WriteLine("Hello from thread '{0}'.", 
                  Thread.CurrentThread.Name);
    taskA.Wait();
}

public static void Main()
{
    Thread.CurrentThread.Name = "Main";

    // Define and run the task.
    Task taskA = Task.Run( () => Console.WriteLine("Hello from taskA."));

    // Output a message from the calling thread.
    Console.WriteLine("Hello from thread '{0}'.", 
                      Thread.CurrentThread.Name);
    taskA.Wait();
}

public static void Main()
{
    Thread.CurrentThread.Name = "Main";

    // Better: Create and start the task in one operation. 
    Task taskA = Task.Factory.StartNew(() => Console.WriteLine("Hello from taskA."));

    // Output a message from the calling thread.
    Console.WriteLine("Hello from thread '{0}'.", 
                    Thread.CurrentThread.Name);

    taskA.Wait();                  
}

Ja po prostu nie rozumiem, dlaczego MS daje 3 różne sposoby uruchamiania zadań w OC, ponieważ wszystkie działają tak samo: Task.Start(), Task.Run()i Task.Factory.StartNew().

Powiedz mi, są Task.Start(), Task.Run()i Task.Factory.StartNew()używane w tym samym celu lub mają one inne znaczenie?

Kiedy używać Task.Start(), kiedy używać, Task.Run()a kiedy używać Task.Factory.StartNew()?

Proszę, pomóż mi szczegółowo zrozumieć ich rzeczywiste użycie zgodnie ze scenariuszem wraz z przykładami.

Mou
źródło
jest stary artykuł wyjaśniający, że tu i tu dla nowszychTask.Run - może to odpowie na twoje pytanie;)
Carsten
Oto przykład tego, gdzie Task.Startjest rzeczywiście przydatne.
noseratio

Odpowiedzi:

171

Task.Runjest skrótem dla Task.Factory.StartNewz określonymi bezpiecznymi argumentami:

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

Został dodany w .Net 4.5, aby pomóc w coraz częstszym używaniu asynci odciążaniu pracy ThreadPool.

Task.Factory.StartNew(dodane wraz z TPL w .Net 4.0) jest znacznie bardziej niezawodne. Powinieneś go używać tylko wtedy, gdy Task.Runnie wystarczy, na przykład, gdy chcesz użyć TaskCreationOptions.LongRunning(choć jest to niepotrzebne, gdy delegat jest asynchroniczny. Więcej na ten temat na moim blogu: LongRunning Is Useless For Task.Run With async-await ). Więcej na temat Task.Factory.StartNeww Task.Run vs Task.Factory.StartNew

Nigdy nie twórz Taski Start()nie dzwoń, chyba że znajdziesz do tego wyjątkowo dobry powód. Powinien być używany tylko wtedy, gdy masz część, która musi tworzyć zadania, ale nie planujesz ich, a inną część, która planuje bez tworzenia. To prawie nigdy nie jest odpowiednie i może być niebezpieczne. Więcej w „Task.Factory.StartNew” a „nowe zadanie (...). Start”

Podsumowując, najczęściej używaj Task.Run, Task.Factory.StartNewjeśli musisz i nigdy nie używaj Start.

i3arnon
źródło
5
powiedziałeś "Nigdy nie twórz zadania i nie wywołuj Start ()" przekierowuj mnie do jakiegokolwiek dobrego zapisu, który pokaże, że może to być spowodowane przez Task.Start (). Potrzebuję szczegółów, ponieważ mówisz, aby tego uniknąć. dzięki za odpowiedź.
Mou
1
@Mou Task.Startma swoje miejsce głównie do dziedziczenia typów.
Yuval Itzchakov
1
@Mou Jest to nieefektywne, ponieważ wymaga synchronizacji, aby upewnić się, że jest wywoływane tylko raz. Inne opcje nie.
i3arnon
2
@Mou Prawdopodobnie powinieneś przeczytać post wyjaśniający ten problem blogs.msdn.com/b/pfxteam/archive/2010/06/13/10024153.aspx
i3arnon
2

Krótka odpowiedź :

Jeśli nie używasz zagnieżdżonych zadań podrzędnych i zawsze chcesz, aby Twoje zadania były wykonywane w puli wątków , lepiej jest użyć Task.Run.

Długa odpowiedź:

Task.Runi Task.Factory.StartNewoba zapewniają obsługę tworzenia i planowania obiektów Task, więc nie musimy tworzyć Taskpołączeń iStart()

Task.Run(action);

Jest równa:

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

I

Task.Factory.StartNew(action);

Jest równa:

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

Task.Runużywa, TaskCreationOptions.DenyChildAttachco oznacza, że ​​zadania dzieci nie mogą być dołączone do elementu nadrzędnego i używa, TaskScheduler.Defaultco oznacza, że ​​ten, który uruchamia zadania w puli wątków, będzie zawsze używany do uruchamiania zadań.

Task.Factory.StartNewużywa, TaskScheduler.Currentco oznacza harmonogram bieżącego wątku, może być, TaskScheduler.Defaultale nie zawsze.

Ali Bayat
źródło